栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis 输出SQL预编译后的语句及输出可执行的SQL语句

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis 输出SQL预编译后的语句及输出可执行的SQL语句

环境

Mybatis、Druid(DataSource)

原因

业务需要及想进一步了解Mybatis知识。
下面就只写怎么做了,原理就一步一步去debug吧,自己动手能了解更多。

输出SQL预编译语句

共有两个方式能获取预编译后的语句: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。

Druid(DataSource) 过滤器
@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 parameters = new ArrayList<>(parametersSize);
            for (int i = 0; i < parametersSize; i++) {
                JdbcParameter parameter = statement.getParameter(i);
                parameters.add(parameter != null ? parameter.getValue() : null);
            }
            String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType();
            formattedSql = SQLUtils.format(sql, dbType, parameters);
        }
        log.info("执行SQL语句,SQL={}", formattedSql);
    }
}
 

这个是参考了 Druid 的 LogFilter ,直接调用SQLUtils.format(String sql, String dbType, List parameters) 来获取可执行的 sql 语句。

执行顺序

拦截器跟过滤器都是递归方式执行:
正向:Mybatis 拦截器 -> Druid 过滤器
反向:Druid 过滤器 -> Mybatis 拦截器

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号