Mybatis插件使用-統計sql執行時間


  背景介紹:最近由於產品數據量較大,sql執行十分低效,正在做數據庫優化,所以想在日志中看到每個sql執行的時間,以方便針對性的優化。

  查找相關資料,了解到Mybatis有一款插件,是基於interceptor來實現的,可以在攔截器中來輸出每個sql的執行時間,配置方便且簡單,經過自測可用。

  1、在dao的配置文件中,在sqlSessionFactory配置項里添加插件依賴:

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml" />
        <property name="mapperLocations" value="classpath:/sqlmap/*Mapper.xml" />
        <property name="dataSource" ref="dataSource" />
        <property name="plugins">
            <array>
                <!-- 基於攔截器的實現,配置攔截器所在工程的全路徑 -->
                <bean id="sqlStatementInterceptor" class="com.**.interceptor.SqlStatementInterceptor"/>
            </array>
        </property>
    </bean>

  2、在工程com.**.interceptor包路徑下添加SqlStatementInterceptor.java,具體代碼如下:

/**
 * Mybatis SQL攔截器,記錄每個sqlId對應的執行時間
 * 
 * @author yehaixiao
 * @date 2017-09-07
 */
@Intercepts(value = {
        @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 }),
        @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
                RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class }) })
public class SqlStatementInterceptor implements Interceptor {
    private static Logger logger = Logger.getLogger(SqlStatementInterceptor.class);

    @Override
    public Object intercept(Invocation invocation) {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        // sqlId為mapper文件中定義的id,例如:com.**.dao.**Mapper.selectByPrimaryKey
        String sqlId = mappedStatement.getId();
        // 開始時間
        long start = System.currentTimeMillis();
        try {
            return invocation.proceed();
        } catch (Exception e) {
            logger.error(sqlId + "執行失敗!", e);
            return null;
        } finally {
            long end = System.currentTimeMillis();
            long time = end - start;
            StringBuilder str = new StringBuilder();
            str.append(sqlId);
            str.append(": ");
            str.append("cost time ");
            str.append(time);
            str.append(" ms.");
            String sqlInfo = str.toString();
            logger.debug(sqlInfo);
        }
    }

    @Override
    public Object plugin(Object arg0) {
        return Plugin.wrap(arg0, this);
    }

    @Override
    public void setProperties(Properties arg0) {

    }
}

  說明:自定義的攔截器實現了org.apache.ibatis.plugin.Interceptor,Interceptor中有三個方法:

public abstract interface Interceptor {
    public abstract Object intercept(Invocation paramInvocation) throws Throwable;

    public abstract Object plugin(Object paramObject);

    public abstract void setProperties(Properties paramProperties);
}

  我們主要實現了intercept方法,入參是一個Invocation,Invocation的內部結構如下所示:  

    

  第一個參數是長度為4的args數組,數組的第一個參數是一個MappedStatement,其實這個就是執行一個sql對應的對象,該對象中有個getId,獲取到的結果就是mapper文件中sql定義的id,這樣就很容易明白自定義的攔截器里intercept方法里第一句話含義。

  直到現在,相關的配置、代碼以及說明全都結束,在執行sql的時候,日志中可以看到如下輸出:  

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM