手寫mybatis完整sql插件問(wèn)題及實(shí)現(xiàn)思路
問(wèn)題產(chǎn)生
我們?cè)谑褂胢ybatis的過(guò)程中,如果開(kāi)啟了mysql的日志功能的話,會(huì)在控制臺(tái)打印一些sql的信息,但是日志中的sql語(yǔ)句,是沒(méi)有拼接參數(shù)的,也就是說(shuō),是不可以直接放到數(shù)據(jù)庫(kù)中執(zhí)行的。
some times,我們?cè)谡{(diào)試問(wèn)題的時(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
解決思路
通過(guò)思考,我覺(jué)得可以通過(guò)mybatis的插件機(jī)制來(lái)解決這個(gè)問(wèn)題。
首先,我們查看源碼,發(fā)現(xiàn)mysql的PreparedStatement的toString方法中,直接通過(guò)asSql方法展示了完整的sql語(yǔ)句:
其次,mybatis中StatementHandler以及ParameterHandler接口中,都有相應(yīng)的方法能夠攔截到Statement:
具體實(shí)現(xiàn)
我們隨機(jī)選擇攔截ParameterHandler來(lái)進(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ǔ)句打印的有問(wèn)題,綁定的參數(shù)沒(méi)有打印出來(lái)。
仔細(xì)一看,發(fā)現(xiàn)我們攔截的就是ParameterHandler的綁定參數(shù)方法,且是在方法執(zhí)行之前進(jìn)行的打印,顯然,參數(shù)還未綁定,所以我們調(diào)整一下攔截方法的執(zhí)行過(guò)程:
重新執(zhí)行,結(jié)果正常:
以上就是手寫mybatis完整sql插件的詳細(xì)內(nèi)容,更多關(guān)于mybatis完整sql插件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java框架學(xué)習(xí)Struts2復(fù)選框?qū)嵗a
這篇文章主要介紹了Java框架學(xué)習(xí)Struts2復(fù)選框?qū)嵗a,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02Java基于分治算法實(shí)現(xiàn)的棋盤覆蓋問(wèn)題示例
這篇文章主要介紹了Java基于分治算法實(shí)現(xiàn)的棋盤覆蓋問(wèn)題,簡(jiǎn)單描述了棋盤覆蓋問(wèn)題,并結(jié)合具體實(shí)例形式分析了java基于分治算法實(shí)現(xiàn)棋盤覆蓋問(wèn)題的相關(guān)操作技巧,需要的朋友可以參考下2017-11-11SpringCloud如何解決服務(wù)之間的通信問(wèn)題
本文主要介紹了SpringCloud如何解決服務(wù)之間的通信問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-08-08java的main方法中調(diào)用spring的service方式
這篇文章主要介紹了在java的main方法中調(diào)用spring的service方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12JAVA演示阿里云圖像識(shí)別API,印刷文字識(shí)別-營(yíng)業(yè)執(zhí)照識(shí)別
最近有由于工作需要,開(kāi)始接觸阿里云的云市場(chǎng)的印刷文字識(shí)別API-營(yíng)業(yè)執(zhí)照識(shí)別這里我加上了官網(wǎng)的申請(qǐng)說(shuō)明,只要你有阿里云賬號(hào)就可以用,前500次是免費(fèi)的,API說(shuō)明很簡(jiǎn)陋,只能做個(gè)簡(jiǎn)單參考2019-05-05String.intern()作用與常量池關(guān)系示例解析
這篇文章主要為大家介紹了String.intern()作用與常量池關(guān)系示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08開(kāi)源的Java圖片處理庫(kù)實(shí)例詳解
Java?圖片處理庫(kù)提供了豐富的功能,用于處理和增強(qiáng)圖像,在Java生態(tài)系統(tǒng)中,有幾個(gè)流行的開(kāi)源庫(kù)可以用于圖片處理,這些庫(kù)提供了豐富的功能,如圖像縮放、裁剪、顏色調(diào)整、格式轉(zhuǎn)換等,本文介紹開(kāi)源的Java圖片處理庫(kù)介紹,感興趣的朋友一起看看吧2024-03-03Java實(shí)現(xiàn)中國(guó)象棋的示例代碼
中國(guó)象棋是起源于中國(guó)的一種棋,屬于二人對(duì)抗性游戲的一種,在中國(guó)有著悠久的歷史。由于用具簡(jiǎn)單,趣味性強(qiáng),成為流行極為廣泛的棋藝活動(dòng)。本文將利用Java實(shí)現(xiàn)這一經(jīng)典游戲,需要的可以參考一下2022-02-02