亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Mybatis控制臺打印SQL執(zhí)行信息的方法詳解

 更新時間:2024年11月27日 11:31:26   作者:對酒當歌丶人生幾何  
SQL性能監(jiān)控是一個程序必要的功能,通常我們可以使用數(shù)據(jù)庫自帶的客戶端工具進行SQL性能分析,本章節(jié)只實現(xiàn)Mybatis執(zhí)行時對執(zhí)行SQL進行攔截,控制臺打印執(zhí)行SQL包括參數(shù)、執(zhí)行方法以及執(zhí)行時間,需要的朋友可以參考下

前言

SQL性能監(jiān)控是一個程序必要的功能,通常我們可以使用數(shù)據(jù)庫自帶的客戶端工具進行SQL性能分析。然而對于一些專業(yè)度不高的人員來說,當程序出現(xiàn)卡頓或者響應速度變慢時,排查問題變得困難。當程序出現(xiàn)卡頓,通常通過檢查服務器磁盤使用情況、程序內存大小,網(wǎng)絡帶寬以及數(shù)據(jù)庫I/O等方面進行問題排查。然而數(shù)據(jù)庫I/O打高的情況通常是由于SQL執(zhí)行效率過低導致的。一般項目制的公司都有屬于自己的實施人員,然而要讓實施人員去排查具體SQL執(zhí)行過慢問題,這顯然對于專業(yè)度不高的工作人員來說是一種挑戰(zhàn)和煎熬。因此本系列文章將介紹如何使用Mybatis的攔截器功能完成對SQL執(zhí)行的時間記錄,并通過MQ推送至SQL記錄服務,記錄具體的慢SQL信息,后續(xù)可以通過頁面進行展示。通過可視化的方式讓實施人員快速定位到問題所在。

一、基本功能介紹

本章節(jié)只實現(xiàn)Mybatis執(zhí)行時對執(zhí)行SQL進行攔截,控制臺打印執(zhí)行SQL包括參數(shù)、執(zhí)行方法以及執(zhí)行時間。大致結構圖如下:

1.1本章功能效果預覽圖:

Mapper Method: 顯示該SQL是由哪個Mapper方法進行調用執(zhí)行。
Execute SQL:打印出完整執(zhí)行的SQL,自動填充了參數(shù)。
Spend Time:記錄本次SQL執(zhí)行花費的時間。

二、可執(zhí)行源碼

2.1 yaml基礎配置

需要在yaml配置文件中配置是否打印SQL執(zhí)行信息。當然該配置可以放入Redis中,以方便后續(xù)面向微服務時,可以一鍵開啟和關閉,這里就不再演示,后續(xù)擴展可有您自主實現(xiàn)。

mybatis-analyze:
  show-log: true #SQL打印到控制臺

2.2 MybatisAnalyzeSQLInterceptor實現(xiàn)SQL攔截

源碼可直接復制運行?。。。?!

package com.hl.by.common.mybatis.interceptor;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
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.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: DI.YIN
 * @Date: 2024/11/25 16:32
 * @Version: 1.0.0
 * @Description: Mybatis SQL分析插件
 **/
@Slf4j
@Intercepts(value = {
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
        @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}),
})
@Component
public class MybatisAnalyzeSQLInterceptor implements Interceptor {

    @Value("${mybatis-analyze.show-log:false}")
    private Boolean showLog;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        StopWatch startedWatch = StopWatch.createStarted();
        Object returnValue = null;
        Exception proceedSQLException = null;
        try {
            returnValue = invocation.proceed();
        } catch (Exception e) {
            proceedSQLException = e;
        }
        startedWatch.stop();
        long spendTime = startedWatch.getTime(TimeUnit.MILLISECONDS);
        if (invocation.getArgs() == null || !(invocation.getArgs()[0] instanceof MappedStatement)) {
            return returnValue;
        }
        // just handle mappedStatement
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        // get BoundSql
        BoundSql boundSql = null;
        for (int i = invocation.getArgs().length - 1; i >= 0; i--) {
            if (invocation.getArgs()[i] instanceof BoundSql) {
                boundSql = (BoundSql) invocation.getArgs()[i];
                break;
            }
        }
        if (invocation.getTarget() instanceof RoutingStatementHandler) {
            RoutingStatementHandler routingStatementHandler = (RoutingStatementHandler) invocation.getTarget();
            boundSql = routingStatementHandler.getBoundSql();
        }
        if (boundSql == null) {
            Object parameter = null;
            if (invocation.getArgs().length > 1) {
                parameter = invocation.getArgs()[1];
            }
            boundSql = mappedStatement.getBoundSql(parameter);
        }
        //
        printProcessedSQL(boundSql, mappedStatement.getConfiguration(), mappedStatement.getId(), spendTime);
        // If an exception occurs during SQL execution,throw exception
        if (proceedSQLException != null) {
            throw proceedSQLException;
        }
        return returnValue;
    }

    /**
     * Parse SQL and Print SQL
     *
     * @param boundSql
     * @param configuration
     * @param statement
     * @param spendTime
     */
    private void printProcessedSQL(BoundSql boundSql, Configuration configuration, String statement, long spendTime) {
        Map<Integer, Object> parameterValueMap = parseParameterValues(configuration, boundSql);
        String finalSQL = fillSqlParams(boundSql.getSql(), parameterValueMap);
        finalSQL = finalSQL.replaceAll("\n", "");
        String printData = "\n===============Start Print SQL===============\n" +
                "Mapper Method: [ " + statement + " ]\n" +
                "Execute SQL: " + finalSQL + " \n" +
                "Spend Time: " + spendTime + " ms \n" +
                "===============End Print SQL===============\n";
        if (showLog) {
            log.info(printData);
        }
    }

    public static String fillSqlParams(String statementQuery, Map<Integer, Object> parameterValues) {
        final StringBuilder sb = new StringBuilder();
        int currentParameter = 0;
        for (int pos = 0; pos < statementQuery.length(); pos++) {
            char character = statementQuery.charAt(pos);
            if (statementQuery.charAt(pos) == '?' && currentParameter <= parameterValues.size()) {
                Object value = parameterValues.get(currentParameter);
                sb.append(value != null ? value.toString() : new MybatisAnalyzeSQLInterceptor.Values().toString());
                currentParameter++;
            } else {
                sb.append(character);
            }
        }
        return sb.toString();
    }

    /**
     * 用于解析參數(shù)值
     *
     * @param configuration
     * @param boundSql
     * @return Map<Integer, Object>
     */
    private static Map<Integer, Object> parseParameterValues(Configuration configuration, BoundSql boundSql) {
        Object parameterObject = boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings != null) {
            Map<Integer, Object> parameterValues = new HashMap<>();
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            for (int i = 0; i < parameterMappings.size(); i++) {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        MetaObject metaObject = configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
                    parameterValues.put(i, new MybatisAnalyzeSQLInterceptor.Values(value));
                }
            }
            return parameterValues;
        }
        return Collections.emptyMap();
    }

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

    @Override
    public void setProperties(Properties properties0) {
    }

    @Setter
    @Getter
    public static class Values {
        public static final String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

        public static final String databaseDialectDateFormat = NORM_DATETIME_PATTERN;
        public static final String databaseDialectTimestampFormat = NORM_DATETIME_PATTERN;
        private Object value;

        public Values(Object valueToSet) {
            this();
            this.value = valueToSet;
        }

        public Values() {
        }

        @Override
        public String toString() {
            return convertToString(this.value);
        }

        public String convertToString(Object value) {
            String result;

            if (value == null) {
                result = "NULL";
            } else {
                if (value instanceof byte[]) {
                    result = new String((byte[]) value);
                } else if (value instanceof Timestamp) {
                    result = new SimpleDateFormat(databaseDialectTimestampFormat).format(value);
                } else if (value instanceof Date) {
                    result = new SimpleDateFormat(databaseDialectDateFormat).format(value);
                } else if (value instanceof Boolean) {
                    result = Boolean.FALSE.equals(value) ? "0" : "1";
                } else {
                    result = value.toString();
                }
                result = quoteIfNeeded(result, value);
            }

            return result;
        }

        private String quoteIfNeeded(String stringValue, Object obj) {
            if (stringValue == null) {
                return null;
            }
            if (Number.class.isAssignableFrom(obj.getClass()) || Boolean.class.isAssignableFrom(obj.getClass())) {
                return stringValue;
            } else {
                return "'" + escape(stringValue) + "'";
            }
        }

        private String escape(String stringValue) {
            return stringValue.replaceAll("'", "''");
        }
    }
}

到此這篇關于Mybatis控制臺打印SQL執(zhí)行信息的方法詳解的文章就介紹到這了,更多相關Mybatis控制臺打印SQL內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 詳解Spring boot Admin 使用eureka監(jiān)控服務

    詳解Spring boot Admin 使用eureka監(jiān)控服務

    本篇文章主要介紹了詳解Spring boot Admin 使用eureka監(jiān)控服務,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • 幾種常見mybatis分頁的實現(xiàn)方式

    幾種常見mybatis分頁的實現(xiàn)方式

    這篇文章主要介紹了幾種常見mybatis分頁的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Java實現(xiàn)簡單的socket通信教程

    Java實現(xiàn)簡單的socket通信教程

    這篇文章主要介紹了Java實現(xiàn)簡單的socket通信教程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • springboot如何讀取自定義配置項

    springboot如何讀取自定義配置項

    這篇文章主要介紹了springboot如何讀取自定義配置項的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2018-05-05
  • 淺談線性表的原理及簡單實現(xiàn)方法

    淺談線性表的原理及簡單實現(xiàn)方法

    下面小編就為大家?guī)硪黄獪\談線性表的原理及簡單實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • 解決spring data jpa 批量保存更新的問題

    解決spring data jpa 批量保存更新的問題

    這篇文章主要介紹了解決spring data jpa 批量保存更新的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • spring boot啟動后直接關閉了的問題解決

    spring boot啟動后直接關閉了的問題解決

    本文主要介紹了spring boot啟動后直接關閉了的問題解決,SpringBoot項目啟動后自動關閉的原因是未引入web依賴,導致以普通Java項目運行,下面就來介紹一下解決方法,感興趣的可以了解一下
    2025-02-02
  • idea中JRebel不生效問題及解決方案

    idea中JRebel不生效問題及解決方案

    這篇文章主要介紹了idea中JRebel不生效問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Springboot中使用Redis實現(xiàn)分布式鎖的示例代碼

    Springboot中使用Redis實現(xiàn)分布式鎖的示例代碼

    在分布式系統(tǒng)中,為了保證數(shù)據(jù)的一致性和任務的互斥執(zhí)行,分布式鎖是一種常見的解決方案,本文主要介紹了Springboot中使用Redis實現(xiàn)分布式鎖的示例代碼,具有一定的參考價值,感興趣的可以了解一下
    2024-05-05
  • JAVA中的引用與對象詳解

    JAVA中的引用與對象詳解

    本文主要介紹了JAVA中引用與對象的相關知識。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02

最新評論