溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

mybatis 通過攔截器實(shí)現(xiàn)打印完整的sql語句并執(zhí)行結(jié)果

發(fā)布時(shí)間:2020-10-28 17:51:49 來源:億速云 閱讀:1534 作者:Leah 欄目:開發(fā)技術(shù)

本篇文章為大家展示了mybatis 通過攔截器實(shí)現(xiàn)打印完整的sql語句并執(zhí)行結(jié)果,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

開發(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ù)庫(kù)類型的轉(zhuǎn)換
   TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
   // 如果根據(jù)parameterObject.getClass()可以找到對(duì)應(yīng)的類型,則替換
   if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass()))
   {
    sql = sql.replaceFirst("\\&#63;",
     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("\\&#63;",
       Matcher.quoteReplacement(getParameterValue(obj)));
     }
     else if (boundSql.hasAdditionalParameter(propertyName))
     {
      // 該分支是動(dòng)態(tài)sql
      Object obj = boundSql.getAdditionalParameter(propertyName);
      sql = sql.replaceFirst("\\&#63;",
       Matcher.quoteReplacement(getParameterValue(obj)));
     }
     else
     {
      // 打印出缺失,提醒該參數(shù)缺失并防止錯(cuò)位
      sql = sql.replaceFirst("\\&#63;", "缺失");
     }
    }
   }
  }
  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>

上述內(nèi)容就是mybatis 通過攔截器實(shí)現(xiàn)打印完整的sql語句并執(zhí)行結(jié)果,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI