mybatis 通過攔截器打印完整的sql語句以及執(zhí)行結(jié)果操作
開發(fā)過程中,如果使用mybatis做為ORM框架,經(jīng)常需要打印出完整的sql語句以及執(zhí)行的結(jié)果做為參考。
雖然mybatis結(jié)合日志框架可以做到,但打印出來的通常都是sql和參數(shù)分開的。
有時(shí)我們需要調(diào)試這條sql的時(shí)候,就需要把參數(shù)填進(jìn)去,這樣未免有些浪費(fèi)時(shí)間。
此時(shí)我們可以通過實(shí)現(xiàn)mybatis攔截器來做到打印帶參數(shù)的完整的sql,以及結(jié)果通過json輸出到控制臺(tái)。
直接看代碼和使用方法吧:
MyBatis攔截器打印不帶問號(hào)的完整sql語句攔截器
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攔截器打印不帶問號(hào)的完整sql語句
*
* @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語句
MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
Object parameter = null;
// 獲取參數(shù),if語句成立,表示sql語句有參數(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語句的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語句
System.out.println("sql = " + sql);
}
catch (Exception e)
{
e.printStackTrace();
}
// 執(zhí)行完上面的任務(wù)后,不改變?cè)械膕ql執(zhí)行過程
return invocation.proceed();
}
// 封裝了一下sql語句,使得結(jié)果返回完整xml路徑下的sql語句節(jié)點(diǎn)id + sql語句
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語句中多個(gè)空格都用一個(gè)空格代替
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (CollectionUtils.isNotEmpty(parameterMappings) && parameterObject != null)
{
// 獲取類型處理器注冊(cè)器,類型處理器的功能是進(jìn)行java類型和數(shù)據(jù)庫類型的轉(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 通過攔截器打印完整的sql語句以及執(zhí)行結(jié)果操作就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Mybatis控制臺(tái)打印Sql語句的實(shí)現(xiàn)代碼
- Mybatis 實(shí)現(xiàn)打印sql語句的代碼
- mybatis-plus配置控制臺(tái)打印完整帶參數(shù)SQL語句的實(shí)現(xiàn)
- mybatis plus 開啟sql日志打印的方法小結(jié)
- mybatis-plus的sql語句打印問題小結(jié)
- mybatis-plus開啟sql日志打印的三種方法
- Mybatis設(shè)置sql打印日志的多種方法
- mybatis-plus開啟sql打印的三種方式總結(jié)
- MyBatis/mybatis-plus項(xiàng)目打印SQL的方法實(shí)現(xiàn)
相關(guān)文章
簡(jiǎn)述JAVA中堆內(nèi)存與棧內(nèi)存的區(qū)別
這篇文章主要介紹了JAVA中堆內(nèi)存與棧內(nèi)存的區(qū)別,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07
關(guān)于Spring?Cloud的熔斷器監(jiān)控問題
Turbine是一個(gè)聚合Hystrix監(jiān)控?cái)?shù)據(jù)的工具,它可將所有相關(guān)/hystrix.stream端點(diǎn)的數(shù)據(jù)聚合到一個(gè)組合的/turbine.stream中,從而讓集群的監(jiān)控更加方便,接下來通過本文給大家介紹Spring?Cloud的熔斷器監(jiān)控,感興趣的朋友一起看看吧2022-01-01
Mybatis之collection標(biāo)簽中javaType和ofType屬性的區(qū)別說明
這篇文章主要介紹了Mybatis之collection標(biāo)簽中javaType和ofType屬性的區(qū)別說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
Springboot?HTTP如何調(diào)用其他服務(wù)
這篇文章主要介紹了Springboot?HTTP如何調(diào)用其他服務(wù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
Java使用多線程批次查詢大量數(shù)據(jù)(Callable返回?cái)?shù)據(jù))方式
今天給大家分享Java使用多線程批次查詢大量數(shù)據(jù)(Callable返回?cái)?shù)據(jù))方式,多線程有好幾種方式,今天說的方式比較好,實(shí)現(xiàn)Callable<> 這種方式能返回查詢的數(shù)據(jù),加上Future異步獲取方式,查詢效率大大加快,感興趣的朋友一起看看吧2023-11-11
如何利用Java?AWT?創(chuàng)建一個(gè)簡(jiǎn)易計(jì)算器
這篇文章主要介紹了如何利用Java?AWT?創(chuàng)建一個(gè)簡(jiǎn)易計(jì)算器,AWT?是一個(gè)有助于構(gòu)建?GUI?的?API?基于?java?應(yīng)用程序,下面關(guān)于其相關(guān)資料實(shí)現(xiàn)計(jì)算器的內(nèi)容詳細(xì),需要的朋友可以參考一下2022-03-03
對(duì)數(shù)據(jù)進(jìn)行分頁顯示到table中的實(shí)現(xiàn)方法
這篇文章主要介紹了對(duì)數(shù)據(jù)進(jìn)行分頁顯示到table中的實(shí)現(xiàn)方法的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-05-05
springboot整合過濾器實(shí)戰(zhàn)步驟
在項(xiàng)目開發(fā)過程中,過濾器或者攔截器幾乎是必用的,他可以很方便的完成類似日志處理、token驗(yàn)證等一系列操作,區(qū)別于業(yè)務(wù)接口,獨(dú)立進(jìn)行處理,感覺就是一種Aop思想。下面模擬請(qǐng)求接口前的token驗(yàn)證,進(jìn)行過濾器的實(shí)戰(zhàn)2022-04-04

