手寫mybatis完整sql插件問題及實(shí)現(xiàn)思路
問題產(chǎn)生
我們?cè)谑褂胢ybatis的過程中,如果開啟了mysql的日志功能的話,會(huì)在控制臺(tái)打印一些sql的信息,但是日志中的sql語(yǔ)句,是沒有拼接參數(shù)的,也就是說,是不可以直接放到數(shù)據(jù)庫(kù)中執(zhí)行的。
some times,我們?cè)谡{(diào)試問題的時(shí)候,會(huì)希望有一個(gè)直接可以運(yùn)行的SQL語(yǔ)句,那將方便很多,特別是在sql語(yǔ)句綁定參數(shù)很多的時(shí)候。
現(xiàn)象描述
默認(rèn)的mysql日志配置和打印情況如下:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
==> Preparing: select * from hwc_users a where a.name = ? and a.age = ? ==> Parameters: huwenchao(String), 35(Integer) <== Total: 0
解決思路
通過思考,我覺得可以通過mybatis的插件機(jī)制來解決這個(gè)問題。
首先,我們查看源碼,發(fā)現(xiàn)mysql的PreparedStatement的toString方法中,直接通過asSql方法展示了完整的sql語(yǔ)句:

其次,mybatis中StatementHandler以及ParameterHandler接口中,都有相應(yīng)的方法能夠攔截到Statement:


具體實(shí)現(xiàn)
我們隨機(jī)選擇攔截ParameterHandler來進(jìn)行完整sql語(yǔ)句的輸出:
步驟一、編寫攔截器類,并配置攔截的類和方法:
package com.huwc.interceptor;
import com.mysql.jdbc.JDBC42PreparedStatement;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.logging.jdbc.PreparedStatementLogger;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.sql.PreparedStatement;
import java.util.Properties;
@Intercepts({
@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
}
)
public class MybatisLogInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
PreparedStatement statement = (PreparedStatement) invocation.getArgs()[0];
PreparedStatement statement1 = null ;
if(Proxy.isProxyClass(statement.getClass())){
InvocationHandler handler = Proxy.getInvocationHandler(statement);
if(handler.getClass().getName().endsWith(".PreparedStatementLogger")){
Field field = handler.getClass().getDeclaredField("statement");
field.setAccessible(true);
statement1 = (PreparedStatement) field.get(handler);
}
}
System.out.println("================================= execute sql ==============================");
System.out.println(statement1.toString());
System.out.println("================================= execute sql ==============================");
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
步驟二、在mybatis配置文件中進(jìn)行攔截器的注冊(cè):
<plugins>
<plugin interceptor="com.huwc.interceptor.MybatisLogInterceptor"></plugin>
</plugins>
步驟三、測(cè)試結(jié)果:
==> Preparing: select * from hwc_users a where a.name = ? and a.age = ?
================================= execute sql ==============================
com.mysql.jdbc.JDBC42PreparedStatement@53fb3dab: select * from hwc_users a where a.name = ** NOT SPECIFIED ** and a.age = ** NOT SPECIFIED **
================================= execute sql ==============================
==> Parameters: huwenchao(String), 35(Integer)
結(jié)果我們發(fā)現(xiàn)語(yǔ)句打印的有問題,綁定的參數(shù)沒有打印出來。
仔細(xì)一看,發(fā)現(xiàn)我們攔截的就是ParameterHandler的綁定參數(shù)方法,且是在方法執(zhí)行之前進(jìn)行的打印,顯然,參數(shù)還未綁定,所以我們調(diào)整一下攔截方法的執(zhí)行過程:

重新執(zhí)行,結(jié)果正常:

以上就是手寫mybatis完整sql插件的詳細(xì)內(nèi)容,更多關(guān)于mybatis完整sql插件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java中的List和MySQL中的varchar相互轉(zhuǎn)換的解決方案
實(shí)體類中有一個(gè) List<String> 類型的屬性,對(duì)應(yīng)于 MySQL 表里的 varchar 字段,使用 MyBatis 添加或查詢時(shí)能互相轉(zhuǎn)換,本文給大家介紹Java中的List和MySQL中的varchar相互轉(zhuǎn)換的解決方案,需要的朋友可以參考下2024-06-06
基于Spring接口集成Caffeine+Redis兩級(jí)緩存
這篇文章主要介紹了基于Spring接口集成Caffeine+Redis兩級(jí)緩存,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07
Java實(shí)現(xiàn)一個(gè)順序表的完整代碼
順序表是用一段物理地址連續(xù)的存儲(chǔ)單元依次存儲(chǔ)數(shù)據(jù)元素的線性結(jié)構(gòu),一般采用數(shù)組存儲(chǔ)。在數(shù)組上完成數(shù)據(jù)的增刪減改。順序表的底層是一個(gè)數(shù)組2021-04-04
Google?Kaptcha驗(yàn)證碼生成的使用實(shí)例說明
這篇文章主要為大家介紹了Google?Kaptcha驗(yàn)證碼的使用實(shí)例說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
java正則表達(dá)式的應(yīng)用 java讀取文件并獲取電話號(hào)碼
這篇文章主要介紹了java正則表達(dá)式的應(yīng)用,應(yīng)用的內(nèi)容是java讀取文件并獲取電話號(hào)碼,感興趣的小伙伴們可以參考一下2015-11-11
springboot使用單元測(cè)試實(shí)戰(zhàn)
這篇文章主要介紹了springboot使用單元測(cè)試實(shí)戰(zhàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09

