All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor Maven / Gradle / Ivy

/**
 * Copyright (c) 2011-2014, hubin ([email protected]).
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.baomidou.mybatisplus.extension.plugins; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Statement; import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; 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.reflection.MetaObject; import org.apache.ibatis.reflection.SystemMetaObject; import org.apache.ibatis.session.ResultHandler; import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.PluginUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.core.toolkit.SystemClock; import com.baomidou.mybatisplus.core.toolkit.sql.SqlUtils; /** *

* 性能分析拦截器,用于输出每条 SQL 语句及其执行时间 *

* * @author hubin nieqiurong TaoYu * @since 2016-07-07 */ @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})}) public class PerformanceInterceptor implements Interceptor { private static final Log logger = LogFactory.getLog(PerformanceInterceptor.class); private static final String DruidPooledPreparedStatement = "com.alibaba.druid.pool.DruidPooledPreparedStatement"; private static final String T4CPreparedStatement = "oracle.jdbc.driver.T4CPreparedStatement"; private static final String OraclePreparedStatementWrapper = "oracle.jdbc.driver.OraclePreparedStatementWrapper"; /** * SQL 执行最大时长,超过自动停止运行,有助于发现问题。 */ private long maxTime = 0; /** * SQL 是否格式化 */ private boolean format = false; /** * 是否写入日志文件
* true 写入日志文件,不阻断程序执行!
* 超过设定的最大执行时长异常提示! */ private boolean writeInLog = false; private Method oracleGetOriginalSqlMethod; private Method druidGetSQLMethod; @Override public Object intercept(Invocation invocation) throws Throwable { Statement statement; Object firstArg = invocation.getArgs()[0]; if (Proxy.isProxyClass(firstArg.getClass())) { statement = (Statement) SystemMetaObject.forObject(firstArg).getValue("h.statement"); } else { statement = (Statement) firstArg; } MetaObject stmtMetaObj = SystemMetaObject.forObject(statement); try { statement = (Statement) stmtMetaObj.getValue("stmt.statement"); } catch (Exception e) { // do nothing } if (stmtMetaObj.hasGetter("delegate")) { //Hikari try { statement = (Statement) stmtMetaObj.getValue("delegate"); } catch (Exception ignored) { } } String originalSql = null; String stmtClassName = statement.getClass().getName(); if (DruidPooledPreparedStatement.equals(stmtClassName)) { try { if (druidGetSQLMethod == null) { Class clazz = Class.forName(DruidPooledPreparedStatement); druidGetSQLMethod = clazz.getMethod("getSql"); } Object stmtSql = druidGetSQLMethod.invoke(statement); if (stmtSql != null && stmtSql instanceof String) { originalSql = (String) stmtSql; } } catch (Exception ignored) { ignored.printStackTrace(); } } else if (T4CPreparedStatement.equals(stmtClassName) || OraclePreparedStatementWrapper.equals(stmtClassName)) { try { if (oracleGetOriginalSqlMethod != null) { Object stmtSql = oracleGetOriginalSqlMethod.invoke(statement); if (stmtSql != null && stmtSql instanceof String) { originalSql = (String) stmtSql; } } else { Class clazz = Class.forName(stmtClassName); oracleGetOriginalSqlMethod = getMethodRegular(clazz, "getOriginalSql"); if (oracleGetOriginalSqlMethod != null) { //OraclePreparedStatementWrapper is not a public class, need set this. oracleGetOriginalSqlMethod.setAccessible(true); if (null != oracleGetOriginalSqlMethod) { Object stmtSql = oracleGetOriginalSqlMethod.invoke(statement); if (stmtSql != null && stmtSql instanceof String) { originalSql = (String) stmtSql; } } } } } catch (Exception e) { //ignore } } if (originalSql == null) { originalSql = statement.toString(); } originalSql = originalSql.replaceAll("[\\s]+", " "); int index = indexOfSqlStart(originalSql); if (index > 0) { originalSql = originalSql.substring(index, originalSql.length()); } // 计算执行 SQL 耗时 long start = SystemClock.now(); Object result = invocation.proceed(); long timing = SystemClock.now() - start; // 格式化 SQL 打印执行结果 Object target = PluginUtils.realTarget(invocation.getTarget()); MetaObject metaObject = SystemMetaObject.forObject(target); MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); StringBuilder formatSql = new StringBuilder(); formatSql.append(" Time:").append(timing); formatSql.append(" ms - ID:").append(ms.getId()); formatSql.append("\n Execute SQL:").append(SqlUtils.sqlFormat(originalSql, format)).append("\n"); if (this.isWriteInLog()) { if (this.getMaxTime() >= 1 && timing > this.getMaxTime()) { logger.error(formatSql.toString()); } else { logger.debug(formatSql.toString()); } } else { System.err.println(formatSql.toString()); if (this.getMaxTime() >= 1 && timing > this.getMaxTime()) { throw new MybatisPlusException(" The SQL execution time is too large, please optimize ! "); } } return result; } @Override public Object plugin(Object target) { if (target instanceof StatementHandler) { return Plugin.wrap(target, this); } return target; } @Override public void setProperties(Properties prop) { String maxTime = prop.getProperty("maxTime"); String format = prop.getProperty("format"); if (StringUtils.isNotEmpty(maxTime)) { this.maxTime = Long.parseLong(maxTime); } if (StringUtils.isNotEmpty(format)) { this.format = Boolean.valueOf(format); } } public long getMaxTime() { return maxTime; } public PerformanceInterceptor setMaxTime(long maxTime) { this.maxTime = maxTime; return this; } public boolean isFormat() { return format; } public PerformanceInterceptor setFormat(boolean format) { this.format = format; return this; } public boolean isWriteInLog() { return writeInLog; } public PerformanceInterceptor setWriteInLog(boolean writeInLog) { this.writeInLog = writeInLog; return this; } public Method getMethodRegular(Class clazz, String methodName) { if (Object.class.equals(clazz)) { return null; } for (Method method : clazz.getDeclaredMethods()) { if (method.getName().equals(methodName)) { return method; } } return getMethodRegular(clazz.getSuperclass(), methodName); } /** * 获取sql语句开头部分 * * @param sql * @return */ private int indexOfSqlStart(String sql) { String upperCaseSql = sql.toUpperCase(); Set set = new HashSet<>(); set.add(upperCaseSql.indexOf("SELECT ")); set.add(upperCaseSql.indexOf("UPDATE ")); set.add(upperCaseSql.indexOf("INSERT ")); set.add(upperCaseSql.indexOf("DELETE ")); set.remove(-1); if (CollectionUtils.isEmpty(set)) { return -1; } List list = new ArrayList<>(set); list.sort(Comparator.naturalOrder()); return list.get(0); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy