欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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教程

只要添加这个即可<!-- mybatis配置控制台输出sql语句填充占位符-->

<!-- 性能拦截器,兼打印sql,不生产环境配置 -->
<bean id="performanceinterceptor" class="com.baomidou.mybatisplus.plugins.performanceinterceptor">
 <!-- sql 执行最大时长,超过自动停止运行,有助于发现问题。 -->
 <property name="maxtime" value="100"></property>
</bean>

以上这篇mybatis打印替换占位符后的完整sql教程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。