欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Mybatis攔截器打印sql問題

 更新時(shí)間:2023年03月31日 10:24:10   作者:ice?sugar  
這篇文章主要介紹了Mybatis攔截器打印sql問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

在項(xiàng)目中,通常會配置log4j2等來輸出mybatis的sql,為了防止sql注入問題,我們通常會使用#{}的方式來注入sql的參數(shù),這會導(dǎo)致我們拿到的sql日志是沒替換參數(shù)的,參數(shù)都是通過問號?占位符的方式。

當(dāng)我們需要拿下sql去數(shù)據(jù)庫客戶端執(zhí)行的時(shí)候,就會有一個困擾:需要把一個個問號?

替換成對應(yīng)的參數(shù),假設(shè)在insert的sql中插入一個有幾十個字段的表,那將會是一場噩夢。

那有沒有辦法在日志文件記錄完整的sql呢?

詳細(xì)請看下面步驟。

1.log4j2配置修改

關(guān)閉log4j2打印mybatis的sql配置,如果本來就沒開啟,那不需要。

2.配置日志開關(guān)

在springboot的yml文件配置變量logging.sql.enable=true,對攔截器做開關(guān)控制。

3.添加攔截器插件

// 采用自定義攔截器打印sql日志
sessionFactory.setPlugins(new Interceptor[]{this.getSqlLogInterceptor()});

4.攔截器邏輯描述

4.1 注入開關(guān)

?@Value("${logging.sql.enable:true}")
?private Boolean sqlEnable;

4.2 獲取sql

Object target = invocation.getTarget();
StatementHandler statementHandler = (StatementHandler) target;
?//獲取綁定的SQL對象
BoundSql boundSql = statementHandler.getBoundSql();
?//得到需要執(zhí)行的sql語句,并進(jìn)行格式
String sql = boundSql.getSql();

4.2 獲取參數(shù)

//需要綁定的參數(shù)映射對象
List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();

4.3 sql替換參數(shù)

public String buidSql(String sql,Object[] parameters) {
? ? ? ? if (parameters == null || sql == null) {
? ? ? ? ? ? return "";
? ? ? ? }
? ? ? ? List<Object> parametersArray = Arrays.asList(parameters);
? ? ? ? List<Object> list = new ArrayList<Object>(parametersArray);
? ? ? ? while (sql.indexOf("?") != -1 && list.size() > 0 && parameters.length > 0) {
? ? ? ? ? ? Object obj = list.get(0);
? ? ? ? ? ? if(null!=obj && obj instanceof String){
? ? ? ? ? ? ? ? sql = sql.replaceFirst("\\?", "'"+obj.toString()+"'");
? ? ? ? ? ? }else if(null!=obj){
? ? ? ? ? ? ? ? sql = sql.replaceFirst("\\?", obj.toString());
? ? ? ? ? ? }
?
? ? ? ? ? ? list.remove(0);
? ? ? ? }
? ? ? ? return sql.replaceAll("(\r?\n(\\s*\r?\n)+)", "\r\n");
? ? }

4.4 打印sql

log.debug(String.format(
? ? ? ? ? ? ? ? ? ? ? ? "\n########################### ? Sql Start ?###########################" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n StartTime ?: ?%s" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n ExecuteID ?: ?%s" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n ExecuteSQL ?: ?%s" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n ExecuteTime ?: ?%s ms" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n########################### ? Sql End ?###########################\n"
?
? ? ? ? ? ? ? ? ? ? ? ? ,startTimeStr,executeID,this.buidSql(sql,args.toString().split(",")),exeTime));

4.5打印效果

攔截器完整代碼

package com.cloudpaas.plugin.mybatis.interceptor;
?
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
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.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.beans.factory.annotation.Value;
?
import java.lang.reflect.Field;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.*;
?
@Intercepts({
? ? ? ? @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
? ? ? ? @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
? ? ? ? @Signature(type = StatementHandler.class, method = "batch", args = { Statement.class })
})
@Slf4j
public class SqlLogInterceptor implements Interceptor {
? ? private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
?
? ? @Value("${logging.sql.enable:true}")
? ? private Boolean sqlEnable;
?
? ? @Override
? ? public Object intercept(Invocation invocation) throws Throwable {
? ? ? ? if(!sqlEnable){
? ? ? ? ? ? return invocation.proceed();
? ? ? ? }
? ? ? ? Object target = invocation.getTarget();
? ? ? ? MetaObject mObject = SystemMetaObject.forObject(invocation.getTarget());
? ? ? ? MappedStatement mappedStatement = (MappedStatement)mObject.getValue("delegate.mappedStatement");
? ? ? ? // 執(zhí)行的mapper statement ID
? ? ? ? String executeID = mappedStatement.getId();
? ? ? ? //獲取當(dāng)前的開始時(shí)間戳
? ? ? ? long startTime = System.currentTimeMillis();
? ? ? ? //記錄當(dāng)前時(shí)間
? ? ? ? String startTimeStr=sdf.format(new Date());
? ? ? ? StatementHandler statementHandler = (StatementHandler) target;
? ? ? ? try {
? ? ? ? ? ? return invocation.proceed();
? ? ? ? } finally {
? ? ? ? ? ? long endTime = System.currentTimeMillis();
? ? ? ? ? ? //sql的執(zhí)行的時(shí)間
? ? ? ? ? ? long exeTime = endTime - startTime;
? ? ? ? ? ? try{
? ? ? ? ? ? ? ? //獲取綁定的SQL對象
? ? ? ? ? ? ? ? BoundSql boundSql = statementHandler.getBoundSql();
? ? ? ? ? ? ? ? //得到需要執(zhí)行的sql語句,并進(jìn)行格式
? ? ? ? ? ? ? ? String sql = boundSql.getSql();
? ? ? ? ? ? ? ? sql=formatSql(sql);
? ? ? ? ? ? ? ? //得到默認(rèn)的參數(shù)處理器
? ? ? ? ? ? ? ? DefaultParameterHandler dph=(DefaultParameterHandler)statementHandler.getParameterHandler();
? ? ? ? ? ? ? ? //利用反射機(jī)制,從DefaultParameterHandler獲取Configuration和TypeHandlerRegistry
? ? ? ? ? ? ? ? Field configurationField=dph.getClass().getDeclaredField("configuration");
? ? ? ? ? ? ? ? Field typeHandlerRegistryField=dph.getClass().getDeclaredField("typeHandlerRegistry");
? ? ? ? ? ? ? ? //設(shè)置私有屬性可訪問
? ? ? ? ? ? ? ? configurationField.setAccessible(true);
? ? ? ? ? ? ? ? //設(shè)置私有屬性可訪問
? ? ? ? ? ? ? ? typeHandlerRegistryField.setAccessible(true);
? ? ? ? ? ? ? ? Configuration configuration=(Configuration) configurationField.get(dph);
? ? ? ? ? ? ? ? TypeHandlerRegistry typeHandlerRegistry=(TypeHandlerRegistry) typeHandlerRegistryField.get(dph);
? ? ? ? ? ? ? ? //sql的參數(shù)對象
? ? ? ? ? ? ? ? Object parameterObject = boundSql.getParameterObject();
? ? ? ? ? ? ? ? //需要綁定的參數(shù)映射對象
? ? ? ? ? ? ? ? List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();
? ? ? ? ? ? ? ? //處理sql的參數(shù),該部分參考的是DefaultParameterHandler中setParameters方法中的實(shí)現(xiàn)
? ? ? ? ? ? ? ? StringBuffer args=new StringBuffer();
? ? ? ? ? ? ? ? if(parameterMappingList!=null && parameterMappingList.size()>0){
? ? ? ? ? ? ? ? ? ? for(ParameterMapping parameterMapping:parameterMappingList){
? ? ? ? ? ? ? ? ? ? ? ? //如果該參數(shù)不是輸出參數(shù),則進(jìn)行處理
? ? ? ? ? ? ? ? ? ? ? ? if (parameterMapping.getMode() != ParameterMode.OUT) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? Object value;
? ? ? ? ? ? ? ? ? ? ? ? ? ? //參數(shù)的名字,屬性
? ? ? ? ? ? ? ? ? ? ? ? ? ? String propertyName = parameterMapping.getProperty();
? ? ? ? ? ? ? ? ? ? ? ? ? ? //先從附加的,主要是list、array等的處理
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (boundSql.hasAdditionalParameter(propertyName)) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? value = boundSql.getAdditionalParameter(propertyName);
? ? ? ? ? ? ? ? ? ? ? ? ? ? } else if (parameterObject == null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? value = null;
? ? ? ? ? ? ? ? ? ? ? ? ? ? } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //typeHandlerRegistry注冊了某個類的處理
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? value = parameterObject;
? ? ? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //默認(rèn)的MetaObject 的處理,根據(jù)參數(shù)獲取值
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MetaObject metaObject = configuration.newMetaObject(parameterObject);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? value = metaObject.getValue(propertyName);
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? if(value!=null){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(value instanceof Date){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //如果是日期,則格式化一下
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? value=sdf.format(value);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? args.append(",").append(value);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? //刪除第一個逗號
? ? ? ? ? ? ? ? ? ? args.deleteCharAt(0);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? log.debug(String.format(
? ? ? ? ? ? ? ? ? ? ? ? "\n########################### ? Sql Start ?###########################" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n StartTime ?: ?%s" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n ExecuteID ?: ?%s" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n ExecuteSQL ?: ?%s" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n ExecuteTime ?: ?%s ms" +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "\n########################### ? Sql End ?###########################\n"
?
? ? ? ? ? ? ? ? ? ? ? ? ,startTimeStr,executeID,this.buidSql(sql,args.toString().split(",")),exeTime));
? ? ? ? ? ? }catch(Exception e){
? ? ? ? ? ? }
? ? ? ? }
? ? }
?
? ? @Override
? ? public Object plugin(Object target) {
? ? ? ? return Plugin.wrap(target, this);
? ? }
?
? ? @Override
? ? public void setProperties(Properties properties) {
?
? ? }
?
? ? private String formatSql(String sql) {
? ? ? ? // 輸入sql字符串空判斷
? ? ? ? if (sql == null || sql.length() == 0) {
? ? ? ? ? ? return "";
? ? ? ? }
? ? ? ? //格式sql 將回車換行制表符等替換成空,在將連續(xù)多個空格替換成1個空格,然后在去掉左右括號兩邊的空格,在去掉逗號左右兩個的空格
? ? ? ? return sql.replaceAll("[\\t\\n\\x0B\\f\\r]", "").replaceAll(" +", " ")
? ? ? ? ? ? ? ? .replaceAll(" *\\( *", "(").replaceAll(" *\\) *", ")").replaceAll(" *, *", ",");
?
? ? }
?
? ? public String buidSql(String sql,Object[] parameters) {
? ? ? ? if (parameters == null || sql == null) {
? ? ? ? ? ? return "";
? ? ? ? }
? ? ? ? List<Object> parametersArray = Arrays.asList(parameters);
? ? ? ? List<Object> list = new ArrayList<Object>(parametersArray);
? ? ? ? while (sql.indexOf("?") != -1 && list.size() > 0 && parameters.length > 0) {
? ? ? ? ? ? Object obj = list.get(0);
? ? ? ? ? ? if(null!=obj && obj instanceof String){
? ? ? ? ? ? ? ? sql = sql.replaceFirst("\\?", "'"+obj.toString()+"'");
? ? ? ? ? ? }else if(null!=obj){
? ? ? ? ? ? ? ? sql = sql.replaceFirst("\\?", obj.toString());
? ? ? ? ? ? }
?
? ? ? ? ? ? list.remove(0);
? ? ? ? }
? ? ? ? return sql.replaceAll("(\r?\n(\\s*\r?\n)+)", "\r\n");
? ? }
}

總結(jié)

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • MyBatis通用的10種寫法總結(jié)大全

    MyBatis通用的10種寫法總結(jié)大全

    這篇文章主要給大家介紹了關(guān)于MyBatis通用的10種寫法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • java面試LruCache?和?LinkedHashMap及算法實(shí)現(xiàn)

    java面試LruCache?和?LinkedHashMap及算法實(shí)現(xiàn)

    這篇文章主要為大家介紹了java面試LruCache?和?LinkedHashMap及算法實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Mybatis之@ResultMap,@Results,@Result注解的使用

    Mybatis之@ResultMap,@Results,@Result注解的使用

    這篇文章主要介紹了Mybatis之@ResultMap,@Results,@Result注解的使用,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java之JSF框架案例詳解

    Java之JSF框架案例詳解

    這篇文章主要介紹了Java之JSF框架案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • Java和SQL實(shí)現(xiàn)取兩個字符間的值

    Java和SQL實(shí)現(xiàn)取兩個字符間的值

    這篇文章主要介紹了Java和SQL實(shí)現(xiàn)取兩個字符間的值操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Springboot接口項(xiàng)目如何使用AOP記錄日志

    Springboot接口項(xiàng)目如何使用AOP記錄日志

    這篇文章主要介紹了Springboot接口項(xiàng)目如何使用AOP記錄日志,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java中的Runnable,Callable,F(xiàn)uture,F(xiàn)utureTask的比較

    Java中的Runnable,Callable,F(xiàn)uture,F(xiàn)utureTask的比較

    這篇文章主要介紹了Java中的Runnable,Callable,F(xiàn)uture,F(xiàn)utureTask的比較的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Java中輸入與輸出的方法總結(jié)

    Java中輸入與輸出的方法總結(jié)

    這篇文章主要為大家總結(jié)了一下Java中輸入與輸出的三種方法,文中通過示例詳細(xì)的講解了一下這些方法的使用,需要的小伙伴可以參考一下
    2022-04-04
  • 深度剖析Java中的內(nèi)存原型及工作原理

    深度剖析Java中的內(nèi)存原型及工作原理

    這篇文章主要介紹了深度剖析Java中的內(nèi)存原型及工作原理,本文講解了java虛擬機(jī)內(nèi)存原型、常量池、Java內(nèi)存分配中的棧、Java內(nèi)存分配中的堆等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • 詳解JAVA動態(tài)代理

    詳解JAVA動態(tài)代理

    這篇文章主要介紹了JAVA動態(tài)代理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評論