Mybatis打印替換占位符后的完整Sql教程
利用mybtis插件打印完整的sql,將占位符?替換成實(shí)際值
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; //捕獲掉異常,不要影響業(yè)務(wù) 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語(yǔ)句 * * @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); } /** * 將占位符替換成參數(shù)值 * * @param sql * @param configuration * @param boundSql * @return */ private String formatSql(String sql, Configuration configuration, BoundSql boundSql) { //美化sql sql = beautifySql(sql); //填充占位符, 目前基本不用mybatis存儲(chǔ)過(guò)程調(diào)用,故此處不做考慮 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) { // 參數(shù)值 Object value; String propertyName = parameterMapping.getProperty(); // 獲取參數(shù)名稱(chēng) if (boundSql.hasAdditionalParameter(propertyName)) { // 獲取參數(shù)值 value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { // 如果是單個(gè)值則直接賦值 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; } }
補(bǔ)充知識(shí):Mybatis配置控制臺(tái)輸出SQL語(yǔ)句填充占位符
我們使用spring整合mybatis時(shí)候,希望根據(jù)控制臺(tái)輸出的sql語(yǔ)句來(lái)復(fù)制到Navicat等工具去測(cè)試,配置如下
在mybatis的配置文件mybatis-config.xml中配置
<configuration> <!-- | 全局配置設(shè)置 | | 可配置選項(xiàng) 默認(rèn)值, 描述 | | aggressiveLazyLoading true, 當(dāng)設(shè)置為‘true'的時(shí)候,懶加載的對(duì)象可能被任何懶屬性全部加載。否則,每個(gè)屬性都按需加載。 | multipleResultSetsEnabled true, 允許和不允許單條語(yǔ)句返回多個(gè)數(shù)據(jù)集(取決于驅(qū)動(dòng)需求) | useColumnLabel true, 使用列標(biāo)簽代替列名稱(chēng)。不同的驅(qū)動(dòng)器有不同的作法。參考一下驅(qū)動(dòng)器文檔,或者用這兩個(gè)不同的選項(xiàng)進(jìn)行測(cè)試一下。 | useGeneratedKeys false, 允許JDBC 生成主鍵。需要驅(qū)動(dòng)器支持。如果設(shè)為了true,這個(gè)設(shè)置將強(qiáng)制使用被生成的主鍵,有一些驅(qū)動(dòng)器不兼容不過(guò)仍然可以執(zhí)行。 | autoMappingBehavior PARTIAL, 指定MyBatis 是否并且如何來(lái)自動(dòng)映射數(shù)據(jù)表字段與對(duì)象的屬性。PARTIAL將只自動(dòng)映射簡(jiǎn)單的,沒(méi)有嵌套的結(jié)果。FULL 將自動(dòng)映射所有復(fù)雜的結(jié)果。 | defaultExecutorType SIMPLE, 配置和設(shè)定執(zhí)行器,SIMPLE 執(zhí)行器執(zhí)行其它語(yǔ)句。REUSE 執(zhí)行器可能重復(fù)使用prepared statements 語(yǔ)句,BATCH執(zhí)行器可以重復(fù)執(zhí)行語(yǔ)句和批量更新。 | defaultStatementTimeout null, 設(shè)置一個(gè)時(shí)限,以決定讓驅(qū)動(dòng)器等待數(shù)據(jù)庫(kù)回應(yīng)的多長(zhǎng)時(shí)間為超時(shí) | --> <settings> <!-- 這個(gè)配置使全局的映射器啟用或禁用緩存 --> <setting name="cacheEnabled" value="true"/> <!-- 全局啟用或禁用延遲加載。當(dāng)禁用時(shí),所有關(guān)聯(lián)對(duì)象都會(huì)即時(shí)加載 --> <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>
配置上面后就可以在控制臺(tái)輸出sql語(yǔ)句了,但是語(yǔ)句與條件會(huì)分開(kāi)輸出,我們想填充sql語(yǔ)句的占位符的話需要再spring整合mybatis中加配置
只要添加這個(gè)即可<!-- Mybatis配置控制臺(tái)輸出SQL語(yǔ)句填充占位符-->
<!-- 性能攔截器,兼打印sql,不生產(chǎn)環(huán)境配置 --> <bean id="performanceInterceptor" class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"> <!-- SQL 執(zhí)行最大時(shí)長(zhǎng),超過(guò)自動(dòng)停止運(yùn)行,有助于發(fā)現(xiàn)問(wèn)題。 --> <property name="maxTime" value="100"></property> </bean>
以上這篇Mybatis打印替換占位符后的完整Sql教程就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot對(duì)接Spark過(guò)程詳解
這篇文章主要介紹SpringBoot接入Spark的方法的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望能幫助大家解決問(wèn)題2023-02-02IDEA中用maven連接數(shù)據(jù)庫(kù)的教程
這篇文章主要介紹了IDEA中用maven連接數(shù)據(jù)庫(kù)的教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11快速解決idea打開(kāi)某個(gè)項(xiàng)目卡住的問(wèn)題
這篇文章主要介紹了解決idea打開(kāi)某個(gè)項(xiàng)目卡住的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08SpringBoot @PostConstruct原理用法解析
這篇文章主要介紹了SpringBoot @PostConstruct原理用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Java如何通過(guò)ssh遠(yuǎn)程連接主機(jī)并執(zhí)行命令
這篇文章主要介紹了Java如何通過(guò)ssh遠(yuǎn)程連接主機(jī)并執(zhí)行命令問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07SpringBoot?快速實(shí)現(xiàn)分庫(kù)分表的2種方式
本文將為您介紹?ShardingSphere?的一些基礎(chǔ)特性和架構(gòu)組成,以及在?Springboot?環(huán)境下通過(guò)JAVA編碼和Yml配置兩種方式快速實(shí)現(xiàn)分庫(kù)分表功能,感興趣的朋友跟隨小編一起看看吧2023-06-06