mybatis 通过拦截器打印完整的sql语句以及执行结果操作
程序员文章站
2022-06-27 18:33:15
开发过程中,如果使用mybatis做为orm框架,经常需要打印出完整的sql语句以及执行的结果做为参考。虽然mybatis结合日志框架可以做到,但打印出来的通常都是sql和参数分开的。有时我们需要调试...
开发过程中,如果使用mybatis做为orm框架,经常需要打印出完整的sql语句以及执行的结果做为参考。
虽然mybatis结合日志框架可以做到,但打印出来的通常都是sql和参数分开的。
有时我们需要调试这条sql的时候,就需要把参数填进去,这样未免有些浪费时间。
此时我们可以通过实现mybatis拦截器来做到打印带参数的完整的sql,以及结果通过json输出到控制台。
直接看代码和使用方法吧:
mybatis拦截器打印不带问号的完整sql语句拦截器
import java.text.dateformat; import java.util.date; import java.util.list; import java.util.locale; import java.util.properties; import java.util.regex.matcher; import org.apache.commons.collections.collectionutils; 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.reflection.metaobject; import org.apache.ibatis.session.configuration; import org.apache.ibatis.session.resulthandler; import org.apache.ibatis.session.rowbounds; import org.apache.ibatis.type.typehandlerregistry; /** * mybatis拦截器打印不带问号的完整sql语句 * * @author gogym * @version 2018年8月13日 * @see mybatisinterceptor * @since */ @intercepts({ @signature(type = executor.class, method = "update", args = {mappedstatement.class, object.class}), @signature(type = executor.class, method = "query", args = {mappedstatement.class, object.class, rowbounds.class, resulthandler.class})}) @suppresswarnings({"unchecked", "rawtypes"}) public class mybatisinterceptor implements interceptor { @override public object intercept(invocation invocation) throws throwable { try { // 获取xml中的一个select/update/insert/delete节点,是一条sql语句 mappedstatement mappedstatement = (mappedstatement)invocation.getargs()[0]; object parameter = null; // 获取参数,if语句成立,表示sql语句有参数,参数格式是map形式 if (invocation.getargs().length > 1) { parameter = invocation.getargs()[1]; system.out.println("parameter = " + parameter); } string sqlid = mappedstatement.getid(); // 获取到节点的id,即sql语句的id system.out.println("sqlid = " + sqlid); boundsql boundsql = mappedstatement.getboundsql(parameter); // boundsql就是封装mybatis最终产生的sql类 configuration configuration = mappedstatement.getconfiguration(); // 获取节点的配置 string sql = getsql(configuration, boundsql, sqlid); // 获取到最终的sql语句 system.out.println("sql = " + sql); } catch (exception e) { e.printstacktrace(); } // 执行完上面的任务后,不改变原有的sql执行过程 return invocation.proceed(); } // 封装了一下sql语句,使得结果返回完整xml路径下的sql语句节点id + sql语句 public static string getsql(configuration configuration, boundsql boundsql, string sqlid) { string sql = showsql(configuration, boundsql); stringbuilder str = new stringbuilder(100); str.append(sqlid); str.append(":"); str.append(sql); return str.tostring(); } // 如果参数是string,则添加单引号, 如果是日期,则转换为时间格式器并加单引号; 对参数是null和不是null的情况作了处理 private static string getparametervalue(object obj) { string value = null; if (obj instanceof string) { value = "'" + obj.tostring() + "'"; } else if (obj instanceof date) { dateformat formatter = dateformat.getdatetimeinstance(dateformat.default, dateformat.default, locale.china); value = "'" + formatter.format(new date()) + "'"; } else { if (obj != null) { value = obj.tostring(); } else { value = ""; } } return value; } // 进行?的替换 public static string showsql(configuration configuration, boundsql boundsql) { // 获取参数 object parameterobject = boundsql.getparameterobject(); list<parametermapping> parametermappings = boundsql.getparametermappings(); // sql语句中多个空格都用一个空格代替 string sql = boundsql.getsql().replaceall("[\\s]+", " "); if (collectionutils.isnotempty(parametermappings) && parameterobject != null) { // 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换 typehandlerregistry typehandlerregistry = configuration.gettypehandlerregistry(); // 如果根据parameterobject.getclass()可以找到对应的类型,则替换 if (typehandlerregistry.hastypehandler(parameterobject.getclass())) { sql = sql.replacefirst("\\?", matcher.quotereplacement(getparametervalue(parameterobject))); } else { // metaobject主要是封装了originalobject对象,提供了get和set的方法用于获取和设置originalobject的属性值,主要支持对javabean、collection、map三种类型对象的操作 metaobject metaobject = configuration.newmetaobject(parameterobject); for (parametermapping parametermapping : parametermappings) { string propertyname = parametermapping.getproperty(); if (metaobject.hasgetter(propertyname)) { object obj = metaobject.getvalue(propertyname); sql = sql.replacefirst("\\?", matcher.quotereplacement(getparametervalue(obj))); } else if (boundsql.hasadditionalparameter(propertyname)) { // 该分支是动态sql object obj = boundsql.getadditionalparameter(propertyname); sql = sql.replacefirst("\\?", matcher.quotereplacement(getparametervalue(obj))); } else { // 打印出缺失,提醒该参数缺失并防止错位 sql = sql.replacefirst("\\?", "缺失"); } } } } return sql; } @override public object plugin(object target) { return plugin.wrap(target, this); } @override public void setproperties(properties properties) { } }
打印结果拦截器:
import java.util.properties; import org.apache.ibatis.executor.executor; import org.apache.ibatis.mapping.mappedstatement; 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; import org.apache.ibatis.session.rowbounds; import com.poly.rbl.utils.fastjsonutils; /** * 打印结果拦截器 〈功能详细描述〉 * * @author gogym * @version 2019年4月2日 * @see interceptorforqry * @since */ @intercepts({@signature(type = executor.class, method = "query", args = {mappedstatement.class, object.class, rowbounds.class, resulthandler.class})}) public class interceptorforqry implements interceptor { @suppresswarnings({"rawtypes", "unchecked"}) public object intercept(invocation invocation) throws throwable { object result = invocation.proceed(); // 执行请求方法,并将所得结果保存到result中 string str = fastjsonutils.tojsonstring(result); system.out.println(str); return result; } public object plugin(object target) { return plugin.wrap(target, this); } public void setproperties(properties arg0) {} }
用法直接配置在mybatis配置文件里面即可:
<plugins> <!-- 启动sql打印,带参数 <plugin interceptor="com.poly.rbl.plugin.mybatis.mybatisinterceptor"> </plugin> <plugin interceptor="com.poly.rbl.plugin.mybatis.interceptorforqry"> </plugin> </plugins>
以上这篇mybatis 通过拦截器打印完整的sql语句以及执行结果操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
下一篇: 华众服务重新加载方法