Mybatis、Druid(DataSource)
原因业务需要及想进一步了解Mybatis知识。
下面就只写怎么做了,原理就一步一步去debug吧,自己动手能了解更多。
共有两个方式能获取预编译后的语句:Mybatis拦截器、druid过滤器
Mybatis拦截器@Slf4j
@Intercepts({
@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class,
TypeHandlerRegistry.class, Configuration.class})
})
public class SqlOutputInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// invocation.getArgs() 的值是 @Signature 注解里面的 args 列表
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object[] parameterObject = (Object[]) invocation.getArgs()[1];
BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
Configuration configuration = (Configuration) invocation.getArgs()[6];
// 获取未处理的 SQL 字符串
String sql = boundSql.getSql();
// 若想看真正执行的SQL语句,详情请看 DefaultParameterHandler.java 的 setParameters(PreparedStatement ps)
// 输出与编译后的语句,带 “?” 的不可执行语句那种
log.info(sql);
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Interceptor.super.plugin(target);
}
@Override
public void setProperties(Properties properties) {
Interceptor.super.setProperties(properties);
}
}
注意的两个点:
1、BoundSql 存储了预编译后的 sql,是带 “?” 的不可直接执行的sql。
2、可执行的sql语句其实在mybatis发送往数据库前就已经拼好了,但数据是以 byte[] 方式存储的,且 Encoding 是 “utf-8” 存储的。原理上,可以先获取这个 byte[] 以及 Encoding。然后 new String(byte[], Encoding) 的方式直接获取可执行的 sql。
@Slf4j
public class SqlOutputFilter extends FilterEventAdapter {
@Override
public void init(DataSourceProxy dataSource) {
super.init(dataSource);
log.info("初始化SqlOutputFilter。");
}
@Override
protected void statementExecuteAfter(StatementProxy statement, String sql, boolean result) {
super.statementExecuteAfter(statement, sql, result);
log.info("自定义过滤器,在执行操作后执行该方法,输出SQL={}", sql);
int parametersSize = statement.getParametersSize();
String formattedSql = sql;
if (parametersSize > 0) {
List
这个是参考了 Druid 的 LogFilter ,直接调用SQLUtils.format(String sql, String dbType, List parameters) 来获取可执行的 sql 语句。
执行顺序拦截器跟过滤器都是递归方式执行:
正向:Mybatis 拦截器 -> Druid 过滤器
反向:Druid 过滤器 -> Mybatis 拦截器



