您的位置:首页技术文章
文章详情页

Mybatis打印替换占位符后的完整Sql教程

【字号: 日期:2023-10-22 11:48:10浏览:2作者:猪猪

利用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('[sn ]+', ' '); 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 class='com.baomidou.mybatisplus.plugins.PerformanceInterceptor'> <!-- SQL 执行最大时长,超过自动停止运行,有助于发现问题。 --> <property name='maxTime' value='100'></property></bean>

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

标签: Mybatis 数据库
相关文章: