Mybatis打印替换占位符后的完整Sql教程
程序员文章站
2022-06-27 18:44:20
利用mybtis插件打印完整的sql,将占位符?替换成实际值import org.apache.ibatis.cache.cachekey;import org.apache.ibatis.execu...
利用mybtis插件打印完整的sql,将占位符?替换成实际值
import org.apache.ibatis.cache.cachekey; 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.mapping.parametermode; 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; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.context.annotation.profile; import org.springframework.stereotype.component; import java.text.simpledateformat; import java.util.arraylist; import java.util.date; import java.util.list; import java.util.properties; /** * 打印sql * * @date 2019/1/14 20:13 */ @component @profile({"dev", "test"}) @intercepts({ @signature(type = executor.class, method = "query", args = {mappedstatement.class, object.class, rowbounds.class, resulthandler.class}), @signature(type = executor.class, method = "query", args = {mappedstatement.class, object.class, rowbounds.class, resulthandler.class, cachekey.class, boundsql.class}), @signature(type = executor.class, method = "update", args = {mappedstatement.class, object.class})} ) public class sqlinterceptor implements interceptor { private static threadlocal<simpledateformat> datetimeformatter = new threadlocal<simpledateformat>() { @override protected simpledateformat initialvalue() { return new simpledateformat("yyyy-mm-dd hh:mm:ss"); } }; @override public object intercept(invocation invocation) throws throwable { object result = null; //捕获掉异常,不要影响业务 try { mappedstatement mappedstatement = (mappedstatement) invocation.getargs()[0]; object parameter = null; if (invocation.getargs().length > 1) { parameter = invocation.getargs()[1]; } string sqlid = mappedstatement.getid(); boundsql boundsql = mappedstatement.getboundsql(parameter); configuration configuration = mappedstatement.getconfiguration(); long starttime = system.currenttimemillis(); try { result = invocation.proceed(); } finally { long endtime = system.currenttimemillis(); long sqlcosttime = endtime - starttime; string sql = this.getsql(configuration, boundsql); this.formatsqllog(sqlid, sql, sqlcosttime, result); } return result; } catch (exception e) { return result; } } @override public object plugin(object target) { if (target instanceof executor) { return plugin.wrap(target, this); } return target; } @override public void setproperties(properties properties) { } /** * 获取完整的sql语句 * * @param configuration * @param boundsql * @return */ private string getsql(configuration configuration, boundsql boundsql) { // 输入sql字符串空判断 string sql = boundsql.getsql(); if (stringutil.isempty(sql)) { return ""; } return formatsql(sql, configuration, boundsql); } /** * 将占位符替换成参数值 * * @param sql * @param configuration * @param boundsql * @return */ private string formatsql(string sql, configuration configuration, boundsql boundsql) { //美化sql sql = beautifysql(sql); //填充占位符, 目前基本不用mybatis存储过程调用,故此处不做考虑 object parameterobject = boundsql.getparameterobject(); list<parametermapping> parametermappings = boundsql.getparametermappings(); typehandlerregistry typehandlerregistry = configuration.gettypehandlerregistry(); list<string> parameters = new arraylist<>(); if (parametermappings != null) { metaobject metaobject = parameterobject == null ? null : configuration.newmetaobject(parameterobject); for (int i = 0; i < parametermappings.size(); i++) { parametermapping parametermapping = parametermappings.get(i); if (parametermapping.getmode() != parametermode.out) { // 参数值 object value; string propertyname = parametermapping.getproperty(); // 获取参数名称 if (boundsql.hasadditionalparameter(propertyname)) { // 获取参数值 value = boundsql.getadditionalparameter(propertyname); } else if (parameterobject == null) { value = null; } else if (typehandlerregistry.hastypehandler(parameterobject.getclass())) { // 如果是单个值则直接赋值 value = parameterobject; } else { value = metaobject == null ? null : metaobject.getvalue(propertyname); } if (value instanceof number) { parameters.add(string.valueof(value)); } else { stringbuilder builder = new stringbuilder(); builder.append("'"); if (value instanceof date) { builder.append(datetimeformatter.get().format((date) value)); } else if (value instanceof string) { builder.append(value); } builder.append("'"); parameters.add(builder.tostring()); } } } } for (string value : parameters) { sql = sql.replacefirst("\\?", value); } return sql; } /** * 格式化sql日志 * * @param sqlid * @param sql * @param costtime * @return */ private void formatsqllog(string sqlid, string sql, long costtime, object obj) { string sqllog = "==> " + sql; stringbuffer result = new stringbuffer(); if (obj instanceof list) { list list = (list) obj; int count = list.size(); result.append("<== total: " + count); } else if (obj instanceof integer) { result.append("<== total: " + obj); } result.append(" spend time ==> " + costtime + " ms"); logger log = loggerfactory.getlogger(sqlid); log.info(sqllog); log.info(result.tostring()); } public static string beautifysql(string sql) { sql = sql.replaceall("[\\s\n ]+", " "); return sql; } }
补充知识:mybatis配置控制台输出sql语句填充占位符
我们使用spring整合mybatis时候,希望根据控制台输出的sql语句来复制到navicat等工具去测试,配置如下
在mybatis的配置文件mybatis-config.xml中配置
<configuration> <!-- | 全局配置设置 | | 可配置选项 默认值, 描述 | | aggressivelazyloading true, 当设置为‘true'的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。 | multipleresultsetsenabled true, 允许和不允许单条语句返回多个数据集(取决于驱动需求) | usecolumnlabel true, 使用列标签代替列名称。不同的驱动器有不同的作法。参考一下驱动器文档,或者用这两个不同的选项进行测试一下。 | usegeneratedkeys false, 允许jdbc 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。 | automappingbehavior partial, 指定mybatis 是否并且如何来自动映射数据表字段与对象的属性。partial将只自动映射简单的,没有嵌套的结果。full 将自动映射所有复杂的结果。 | defaultexecutortype simple, 配置和设定执行器,simple 执行器执行其它语句。reuse 执行器可能重复使用prepared statements 语句,batch执行器可以重复执行语句和批量更新。 | defaultstatementtimeout null, 设置一个时限,以决定让驱动器等待数据库回应的多长时间为超时 | --> <settings> <!-- 这个配置使全局的映射器启用或禁用缓存 --> <setting name="cacheenabled" value="true"/> <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 --> <setting name="lazyloadingenabled" value="false"/> <setting name="multipleresultsetsenabled" value="true"/> <setting name="usecolumnlabel" value="true"/> <setting name="logimpl" value="stdout_logging" /> <setting name="defaultexecutortype" value="reuse"/> <setting name="defaultstatementtimeout" value="25000"/> <setting name="aggressivelazyloading" value="true"/> </settings> </configuration>
配置上面后就可以在控制台输出sql语句了,但是语句与条件会分开输出,我们想填充sql语句的占位符的话需要再spring整合mybatis中加配置
只要添加这个即可<!-- mybatis配置控制台输出sql语句填充占位符-->
<!-- 性能拦截器,兼打印sql,不生产环境配置 --> <bean id="performanceinterceptor" class="com.baomidou.mybatisplus.plugins.performanceinterceptor"> <!-- sql 执行最大时长,超过自动停止运行,有助于发现问题。 --> <property name="maxtime" value="100"></property> </bean>
以上这篇mybatis打印替换占位符后的完整sql教程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。