mybatis 通過(guò)攔截器打印完整的sql語(yǔ)句以及執(zhí)行結(jié)果操作
開(kāi)發(fā)過(guò)程中,如果使用mybatis做為ORM框架,經(jīng)常需要打印出完整的sql語(yǔ)句以及執(zhí)行的結(jié)果做為參考。
雖然mybatis結(jié)合日志框架可以做到,但打印出來(lái)的通常都是sql和參數(shù)分開(kāi)的。
有時(shí)我們需要調(diào)試這條sql的時(shí)候,就需要把參數(shù)填進(jìn)去,這樣未免有些浪費(fèi)時(shí)間。
此時(shí)我們可以通過(guò)實(shí)現(xiàn)mybatis攔截器來(lái)做到打印帶參數(shù)的完整的sql,以及結(jié)果通過(guò)json輸出到控制臺(tái)。
直接看代碼和使用方法吧:
MyBatis攔截器打印不帶問(wèn)號(hào)的完整sql語(yǔ)句攔截器
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攔截器打印不帶問(wèn)號(hào)的完整sql語(yǔ)句
*
* @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中的一個(gè)select/update/insert/delete節(jié)點(diǎn),是一條SQL語(yǔ)句
MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
Object parameter = null;
// 獲取參數(shù),if語(yǔ)句成立,表示sql語(yǔ)句有參數(shù),參數(shù)格式是map形式
if (invocation.getArgs().length > 1)
{
parameter = invocation.getArgs()[1];
System.out.println("parameter = " + parameter);
}
String sqlId = mappedStatement.getId(); // 獲取到節(jié)點(diǎn)的id,即sql語(yǔ)句的id
System.out.println("sqlId = " + sqlId);
BoundSql boundSql = mappedStatement.getBoundSql(parameter); // BoundSql就是封裝myBatis最終產(chǎn)生的sql類
Configuration configuration = mappedStatement.getConfiguration(); // 獲取節(jié)點(diǎn)的配置
String sql = getSql(configuration, boundSql, sqlId); // 獲取到最終的sql語(yǔ)句
System.out.println("sql = " + sql);
}
catch (Exception e)
{
e.printStackTrace();
}
// 執(zhí)行完上面的任務(wù)后,不改變?cè)械膕ql執(zhí)行過(guò)程
return invocation.proceed();
}
// 封裝了一下sql語(yǔ)句,使得結(jié)果返回完整xml路徑下的sql語(yǔ)句節(jié)點(diǎn)id + sql語(yǔ)句
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();
}
// 如果參數(shù)是String,則添加單引號(hào), 如果是日期,則轉(zhuǎn)換為時(shí)間格式器并加單引號(hào); 對(duì)參數(shù)是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;
}
// 進(jìn)行?的替換
public static String showSql(Configuration configuration, BoundSql boundSql)
{
// 獲取參數(shù)
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// sql語(yǔ)句中多個(gè)空格都用一個(gè)空格代替
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (CollectionUtils.isNotEmpty(parameterMappings) && parameterObject != null)
{
// 獲取類型處理器注冊(cè)器,類型處理器的功能是進(jìn)行java類型和數(shù)據(jù)庫(kù)類型的轉(zhuǎn)換
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
// 如果根據(jù)parameterObject.getClass()可以找到對(duì)應(yīng)的類型,則替換
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass()))
{
sql = sql.replaceFirst("\\?",
Matcher.quoteReplacement(getParameterValue(parameterObject)));
}
else
{
// MetaObject主要是封裝了originalObject對(duì)象,提供了get和set的方法用于獲取和設(shè)置originalObject的屬性值,主要支持對(duì)JavaBean、Collection、Map三種類型對(duì)象的操作
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))
{
// 該分支是動(dòng)態(tài)sql
Object obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?",
Matcher.quoteReplacement(getParameterValue(obj)));
}
else
{
// 打印出缺失,提醒該參數(shù)缺失并防止錯(cuò)位
sql = sql.replaceFirst("\\?", "缺失");
}
}
}
}
return sql;
}
@Override
public Object plugin(Object target)
{
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties)
{
}
}
打印結(jié)果攔截器:
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;
/**
* 打印結(jié)果攔截器 〈功能詳細(xì)描述〉
*
* @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(); // 執(zhí)行請(qǐng)求方法,并將所得結(jié)果保存到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>
<!-- 啟動(dòng)SQL打印,帶參數(shù)
<plugin interceptor="com.poly.rbl.plugin.mybatis.MybatisInterceptor">
</plugin>
<plugin interceptor="com.poly.rbl.plugin.mybatis.InterceptorForQry">
</plugin>
</plugins>
以上這篇mybatis 通過(guò)攔截器打印完整的sql語(yǔ)句以及執(zhí)行結(jié)果操作就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Mybatis控制臺(tái)打印Sql語(yǔ)句的實(shí)現(xiàn)代碼
- Mybatis 實(shí)現(xiàn)打印sql語(yǔ)句的代碼
- mybatis-plus配置控制臺(tái)打印完整帶參數(shù)SQL語(yǔ)句的實(shí)現(xiàn)
- mybatis plus 開(kāi)啟sql日志打印的方法小結(jié)
- mybatis-plus的sql語(yǔ)句打印問(wèn)題小結(jié)
- mybatis-plus開(kāi)啟sql日志打印的三種方法
- Mybatis設(shè)置sql打印日志的多種方法
- mybatis-plus開(kāi)啟sql打印的三種方式總結(jié)
- MyBatis/mybatis-plus項(xiàng)目打印SQL的方法實(shí)現(xiàn)
相關(guān)文章
SpringBoot攔截器實(shí)現(xiàn)登錄攔截的示例代碼
本文主要介紹了SpringBoot攔截器實(shí)現(xiàn)登錄攔截,文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
解決springboot遇到autowire注入為null的問(wèn)題
這篇文章主要介紹了解決springboot遇到autowire注入為null的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03
SpringBoot如何基于POI-tl和word模板導(dǎo)出龐大的Word文件
這篇文章主要介紹了SpringBoot如何基于POI-tl和word模板導(dǎo)出龐大的Word文件,poi-tl是一個(gè)基于Apache?POI的Word模板引擎,也是一個(gè)免費(fèi)開(kāi)源的Java類庫(kù)2022-08-08
Spring IOC的相關(guān)注解運(yùn)用詳解
這篇文章主要介紹了Spring IOC的相關(guān)注解運(yùn)用詳解,純注解實(shí)現(xiàn)IOC需要一個(gè)Java類代替xml文件,這個(gè)Java類上方需要添加@Configuration,表示該類是一個(gè)配置類,作用是代替配置文件,需要的朋友可以參考下2023-08-08
詳解使用Spring?Data?repository進(jìn)行數(shù)據(jù)層的訪問(wèn)問(wèn)題
這篇文章主要介紹了使用Spring?Data?repository進(jìn)行數(shù)據(jù)層的訪問(wèn),抽象出Spring Data repository是因?yàn)樵陂_(kāi)發(fā)過(guò)程中,常常會(huì)為了實(shí)現(xiàn)不同持久化存儲(chǔ)的數(shù)據(jù)訪問(wèn)層而寫大量的大同小異的代碼,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-06-06
新手了解java 數(shù)組基礎(chǔ)知識(shí)
這篇文章主要介紹了Java 數(shù)組分析及簡(jiǎn)單實(shí)例的相關(guān)資料,在Java中它就是對(duì)象,一個(gè)比較特殊的對(duì)象,需要的朋友可以參考下,希望可以對(duì)你有所幫助2021-07-07
新版idea創(chuàng)建spring boot項(xiàng)目的詳細(xì)教程
這篇文章給大家介紹了新版idea創(chuàng)建spring boot項(xiàng)目的詳細(xì)教程,本教程對(duì)新手小白友好,若根據(jù)教程創(chuàng)建出現(xiàn)問(wèn)題導(dǎo)致失敗可下載我提供的源碼,在文章最后,本教程較新,文中通過(guò)圖文給大家介紹的非常詳細(xì),感興趣的朋友可以參考下2024-01-01

