Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 28 | 29 | 30 |
Tags
- BPMN
- react
- nodejs
- Git
- LOG4J
- tibero
- VSCode
- mybatis
- kubectl
- JavaScript
- database
- NCP
- Windows
- nginx
- Kubernetes
- docker
- jetbrains
- MySQL
- dbeaver
- log4j2
- gson
- JPA
- gradle
- intellijIDEA
- wildfly
- Java
- IntelliJ
- Spring
- useEffect
- springboot
Archives
- Today
- Total
두 손끝의 창조자
MyBatis Sql 과 파라미터 출력하기 본문
MyBatis는 특정 메소드를 인터셉트 할 수 있는 애노테이션인 Intercepts
을 제공한다.Intercepts
의 값으로 메소드 시그니처를 지정해야하는데 메소드 시그니처를 지정하는 애노테이션이 Signature
이다.
메소드 시그니처는 메소드이름과 파라미터 타입이므로 인터셉트 할 메소드를 정확하게 지정한다. 예를 들어 org.apache.ibatis.executor.Executor
인터페이스는
...
int update(MappedStatement ms, Object parameter) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
...
등의 오퍼레이션을 정의하고 있는데 위 오퍼레이션을 구현한 메소드를 인터셉트 하려면 아래 코드처럼 인터셉트 설정을 해야 한다.
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
, @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
}
)
메소드가 인터셉트되면 org.apache.ibatis.plugin.Invocation
클래스에 호출된 메소드와 컨텍스트를 담아서 사용할 수 있도록 해준다.
org.apache.ibatis.plugin.Invocation
인스턴스가 가지고 있는 데이터를 이용하여 로그를 남기는 코드를 작성하였다.
package com.dongkuk.dmes.cr.frm.access.log;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Properties;
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
, @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
}
)
public class MybatisSqlLogger implements Interceptor {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MybatisSqlLogger.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
String queryID = ((MappedStatement) invocation.getArgs()[0]).getId();
Object param = invocation.getArgs()[1];
BoundSql boundSql = ((MappedStatement) invocation.getArgs()[0]).getBoundSql(param);
String queryString = boundSql.getSql();
log.info("\n/* {} */\n{}", queryID, queryString);
for (int i = 0; i < boundSql.getParameterMappings().size(); i++) {
ParameterMapping parameterMapping = boundSql.getParameterMappings().get(i);
Object bindObject = getObject(boundSql.getParameterObject(), parameterMapping);
log.info("binding parameter [{}] as [{}] - [{}]", i, bindObject.getClass().getName(), bindObject);
}
return invocation.proceed();
}
private Object getObject(Object parameterObject, ParameterMapping parameterMapping) throws IllegalAccessException, NoSuchFieldException {
if (parameterObject instanceof Number || parameterObject instanceof String)
return parameterObject;
else if (parameterObject instanceof Map) {
String property = parameterMapping.getProperty();
return ((Map<?, ?>) parameterObject).get(property);
} else {
Class<?> aClass = parameterObject.getClass();
String property = parameterMapping.getProperty();
Field declaredField = null;
try {
declaredField = aClass.getDeclaredField(property);
} catch (NoSuchFieldException e) {
while (aClass.getSuperclass() != null) {
aClass = aClass.getSuperclass();
try {
declaredField = aClass.getDeclaredField(property);
break;
} catch (NoSuchFieldException ignored) {
}
}
}
if (declaredField == null)
throw new NoSuchFieldException(property);
declaredField.setAccessible(true);
return declaredField.get(parameterObject);
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
반응형
Comments