工作中经常希望打印mybatis执行sql的debug日志,上网找到的各种配置都不生效,这是因为mybatis版本不同日志打印方法也不同,下面谈谈开启日志的经验。
第一种方法,是把所有的日志都放开, 然后从中选取自己需要的部分;
第二种方法,从原理层解决是看mybatis源代码,找到打日志的代码,这里选取两个版本观看:
-
3.0.1版,
public class PreparedStatementLogger extends BaseJdbcLogger implements InvocationHandler {
private static final Log log = LogFactory.getLog(PreparedStatement.class);
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
try {
if (EXECUTE_METHODS.contains(method.getName())) {
if (log.isDebugEnabled()) {
log.debug("==> Executing: " + removeBreakingWhitespace(sql));
log.debug("==> Parameters: " + getParameterValueString());
}
......//省略
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
}
看PreparedStatementLogger的invoke方法,log是通过java.sql.PreparedStatement初始化的日志,所以log4j配置方式为:log4j.logger.java.sql.PreparedStatement=DEBUG
2. 3.2.8版,
ConnectionLogger和PreparedStatementLogger均继承至BaseJdbcLogger,看BaseJdbcLogger的debug方法知道其log是构造方法传过来的
public abstract class BaseJdbcLogger {
protected Log statementLog;
public BaseJdbcLogger(Log log, int queryStack) {
this.statementLog = log;
if (queryStack == 0)
queryStack = 1;
this.queryStack = queryStack;
}
protected void debug(String text, boolean input) {
if (statementLog.isDebugEnabled()) {
statementLog.debug(prefix(input) + text);
}
}
}
跟踪调用栈找到该log实例是MappedStatement里面传过来的,看MappedStatement构造:
public final class MappedStatement {
private MappedStatement() {
// constructor disabled
}
public static class Builder {
private MappedStatement mappedStatement = new MappedStatement();
public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) {
mappedStatement.configuration = configuration;
mappedStatement.id = id;//mappedStatement的唯一标识,namespace+id
mappedStatement.sqlSource = sqlSource;
mappedStatement.statementType = StatementType.PREPARED;
mappedStatement.parameterMap = new ParameterMap.Builder(configuration, "defaultParameterMap", null,
new ArrayList<ParameterMapping>()).build();
mappedStatement.resultMaps = new ArrayList<ResultMap>();
mappedStatement.timeout = configuration.getDefaultStatementTimeout();
mappedStatement.sqlCommandType = sqlCommandType;
mappedStatement.keyGenerator = configuration.isUseGeneratedKeys()
&& SqlCommandType.INSERT.equals(sqlCommandType) ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
String logId = id;
if (configuration.getLogPrefix() != null)//可以加前缀
logId = configuration.getLogPrefix() + id;
//这边是构造log的地方
mappedStatement.statementLog = LogFactory.getLog(logId);
mappedStatement.lang = configuration.getDefaultScriptingLanuageInstance();
}
}
}
看log是根据MappedStatement的id创建的,这里的id是namespace+id,所以log4j的写法应该是:
log4j.logger.com.xxx.mapper=DEBUG
com.xxx.mapper是每个业务的包名,如果业务很多,就每个需要打印日志的包路径都写一遍,麻烦!看到上面代码还有一个关键元素configuration.getLogPrefix(),这个前缀是在解析配置的时候获取的,配置这个前缀就可以所以log用一个logger配置。如下:
<settings>
<setting name="logPrefix" value="abcdefg" />
</settings>
log4j.logger.abcdefg=DEBUG