Spring boot P6Spy Log
Spring boot P6Spy Log
Spring Boot 에 MyBatis 를 사용하지 않고 JPA 를 사용 시 JPA 쿼리 로그에서는 파라미터에 ? 가 붙어 있다 .
일단 회사에서 사용하는 쿼리문과 소스코드는 가져 올 수 없기 때문에 예시로 작성 해본다.
1
SELECT * FROM member WHERE id = ?
만약 JPA 로 member 라는 Entity 에 id 로 전부 조회시 id는 ? 로 보인다.
이 ?는 실제 값을 나중에 바인딩 하는 방식으로 SQL 을 실행 하기 때문이다.
이렇게 JPA 가 실행 하는 이유는 간단하게
- 보안 (SQL Injection 을 방지)
- 성능 (DB 가 미리 SQL 쿼리를 컴파일 하고 준비 해 두었다가 같은 형태에 쿼리가 반복 될 경우 빠르게 실행)
- 재사용 및 효율 ( 쿼리 파싱 및 최적화 과정이 감소)
적용 방법
회사에서 사용한 실제 코드가 있다면,,, 작성하기 편하겠지만 코드를 가져올 수 없기 떄문에 적용한 코드와 비슷한 블로그를 참고해서 작성 해본다.
참고 자료 : [SpringBoot] P6Spy query logging 사용하기
위 블로그가 회사에서 적용한 P6Spy 로그와 거의 유사하기 때문에 설명을 작성
우선 필요한 의존성 (dependency)
1 2 3 4 5
# Datasource 방식 / URL연결 방식 implementation 'p6spy:p6spy:3.9.1' # SpringBoot 자동설정 방식 implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.8.1'yml 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url : jdbc:p6spy:oracle:thin:@localhost/
username:
password:
logging:
level:
p6spy: info
decorator:
datasource:
p6spy:
enable-logging: true
2-1 Spy.Properties
https://p6spy.readthedocs.io/en/latest/install.html
1
2
3
4
5
6
# Spring Boot 환경에서 권장되는 기본 설정 예시
appender=com.p6spy.engine.spy.appender.Slf4JLogger
logMessageFormat=com.p6spy.engine.spy.appender.MultiLineFormat
useLogPrefix=true
excludecategories=info,debug,result,batch
logfile=spy.log
properties 는 상당히 많은 옵션을 가지고 있으며 설정은 위 링크를 참고하고 만들면 된다.
Custom Format
출력 되는 쿼리 로그를 커스텀 하는 @Config 가 필요하다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
@Configuration public class P6SpyFomatter implements MessageFormattingStrategy { @PostConstruct public void setLogMessageFormat() { P6SpyOptions.getActiveInstance().setLogMessageFormat(this.getClass().getName()); } @Override public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) { sql = formatSql(category, sql); return String.format("[%s] | %d ms | %s", category, elapsed, formatSql(category, sql)); } private String formatSql(String category, String sql) { if (sql != null && !sql.trim().isEmpty() && Category.STATEMENT.getName().equals(category)) { String trimmedSQL = sql.trim().toLowerCase(Locale.ROOT); if (trimmedSQL.startsWith("create") || trimmedSQL.startsWith("alter") || trimmedSQL.startsWith("comment")) { sql = FormatStyle.DDL.getFormatter().format(sql); } else { sql = FormatStyle.BASIC.getFormatter().format(sql); } return sql; } return sql; } }
이렇게 설정하고 실행 시 SQL 에 ? 대신 사용한 Value가 반영 된 것을 확인 할 수 있다.
또한 Spring 2.x 버전과 Spring 3.x 버전에 사용법 차이도 있다.
😅 잘못 알던 지식
처음 JPA를 공부 할 때 프록시 객체를 이용하여 JPA를 호출 한다. 그러기 때문에 JPA 로그에는 (?) 가 붙는 다고 생각 하고 있었다.
하지만, P6Spy 를 찾아보면서 (?) 가 붙는 이유는 프록시 객체와는 전혀 연관 없는 다른 내용이었다.
JPA에 프록시 객체는 DB에 엔티티를 즉시 로딩 하지 않고 Lazy 로딩을 하기 위함 이였고 , 실제 데이터를 요청하는 시점에 DB를 가져오는 것이였다.
물음표가 찍히는 이유는 → 미리 준비된 파라미터 바인딩
프록시 객체의 용도 이유는 → Lazy 로딩을 위한 목적 이였다.
또한,
1
2
3
SELECT member_0.id, member_0.name
FROM member member_0
WHERE member_0.id = ?
이런식으로 entity_0 , column_0 이런 식으로 붙는 것도 Proxy객체를 사용해서 인가?? 였던 생각을 찾아보면서 잘못 된 지식이였던 걸 알게 되었다.
위 .._0 은 단순하게 JPA에서 JPQL → SQL 로 바꿀때, 기계적으로 별칭을 다는 문제 때문이 었다.