본문 바로가기
spring/spring jpa

[SpringBoot] JPA Comment (주석 추가) 설정 방법

by moonsiri 2024. 2. 2.
728x90
반응형

JPA Comment (주석 추가) 설정 방법

 

application.yml

spring:
  jpa:
    properties:
      hibernate:
       show_sql: false
       format_sql: true
       use_sql_comments: true	# sql comments 사용

 

1. JPA Repository에 적용 방법

To apply JPA QueryHints to the queries declared in your repository interface you can use the QueryHints annotation. It takes an array of JPA QueryHint annotations plus a boolean flag to potentially disable the hints applied to the addtional count query triggered when applying pagination.

public interface UserRepository extends Repository<User, Long> {

      @QueryHints({
            @QueryHint(name = org.hibernate.annotations.QueryHints.COMMENT, value = "select user info")
      })
      Optional<User> findByUserId(String userId);
}
더보기

1-1. Custom hibernate interceptor

JPA에 일괄 적용하기

	@Bean
	public EntityManagerFactory entityManagerFactory(DataSource dataSource, StatementInspector jpaCommentMaker) {

		LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
		// ....

		Map<String, Object> properties = new HashMap<>();
		properties.put(AvailableSettings.STATEMENT_INSPECTOR, jpaCommentMaker);
		// ....
		factory.setJpaPropertyMap(properties);
		factory.afterPropertiesSet();

		return factory.getObject();
	}

	@Bean
	public Interceptor hibernateInterceptor() {
		return new JPACommentMaker();
	}
@Component
public class JPACommentMaker implements StatementInspector {
	private static final String COMMENT_FORMAT = "/* %s */\n";

	@Override
	public String inspect(String sql) {
		return QueryContext.get()
			.map(comment -> String.format(COMMENT_FORMAT, comment) + sql)
			.orElse(sql);
	}
}

public class QueryContext {
	private static final ThreadLocal<String> context = new ThreadLocal<>();

	public static void set(String source) {
		context.set(source);
	}

	public static Optional<String> get() {
		return Optional.ofNullable(context.get());
	}

	public static void clear() {
		context.remove();
	}
}

@Aspect
@Component
public class QuerySourceAspect {

	@Pointcut("within(org.springframework.data.repository.Repository+)")
	public void springDataRepository() {}

	@Pointcut("execution(* *..repository..*RepositoryCustom.*(..))")
	public void customRepository() {}

	@Around("springDataRepository() || customRepository()")
	public Object traceRepositoryCall(ProceedingJoinPoint pjp) throws Throwable {
		try {
			Class<?> actualClass;

			Object target = pjp.getTarget();

			// 프록시인 경우: 인터페이스를 직접 가져옴
			if (Proxy.isProxyClass(target.getClass())) {
				Class<?>[] interfaces = target.getClass().getInterfaces();
				actualClass = (interfaces.length > 0) ? interfaces[0] : target.getClass();
			} else {
				actualClass = target.getClass();
			}

			String source = actualClass.getName() + "." + pjp.getSignature().getName();
			QueryContext.set(source);
			return pjp.proceed();
		} finally {
			QueryContext.clear();
		}
	}
}

 

2. QueryDSL에 적용 방법

@Repository
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserRepositoryCustom {

	private final JPAQueryFactory jpaQueryFactory;

	private static final String JPA_COMMENT_KEY = "org.hibernate.comment";

	public User findById(String userId) {
		return jpaQueryFactory.selectFrom(user)
			.where(user.userId.eq(userId))
			.setHint(JPA_COMMENT_KEY, "select user info")
			.fetchOne();
	}
}

 

3. 결과

2024-02-02 15:02:07 [DEBUG] org.hibernate.SQL:128 - 
    /* select user info */ select
        user0_.`user_id` as col_0_0_,
        user0_.`user_nm` as col_1_0_
    from
        `user` user0_ 
    where
        user0_.`user_id`=?

 

[Reference]

https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html#jpa.query-hints

728x90
반응형

댓글