개발을 하다보면 쿼리로그를 ?
나 실제 변수에 들어간 값이 아닌 값이 담겨져 있는 변수로 찍어야 하는 경우가 발생한다.
Mybatis Interceptor를 통해 쿼리를 찍을 수 있다.
import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
@Intercepts({
@Signature(type=StatementHandler.class, method="update", args={Statement.class}),
@Signature(type=StatementHandler.class, method="query", args={Statement.class, ResultHandler.class})
})
public class MybatisInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(MybatisInterceptor.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler handler = (StatementHandler)invocation.getTarget();
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
Object param = handler.getParameterHandler().getParameterObject();
if(param == null) {
sql = sql.replaceFirst("\\?", ":");
} else {
if(param instanceof Integer || param instanceof Long || param instanceof Float || param instanceof Double) {
sql = sql.replaceFirst("\\?", param.toString());
} else if(param instanceof String) {
sql = sql.replaceFirst("\\?", "'" + param + "'");
} else if(param instanceof Map) {
List<ParameterMapping> paramMapping = boundSql.getParameterMappings();
for(ParameterMapping mapping : paramMapping) {
String propValue = mapping.getProperty();
sql = sql.replaceFirst("\\?", ":" + propValue);
}
} else {
List<ParameterMapping> paramMapping = boundSql.getParameterMappings();
for(ParameterMapping mapping : paramMapping) {
String propValue = mapping.getProperty();
sql = sql.replaceFirst("\\?", ":" + propValue);
}
}
}
if(log.isDebugEnabled()) {
log.debug("SQL QUERY :: \n{}", sql);
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// null
}
}
interceptor를 통해 실제 값이 들어가는 부분을 변수로 대체해 쿼리를 찍고 로그레벨이 debug 가 아닐 경우엔 로직을 타지 않도록 설정할 수 있다.
SqlSessionFactory Bean을 생성할 때 plugin 설정에 추가해줄 수 있다.
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setPlugins(new MybatisInterceptor());