/** * Copyright (c) 2011-2014, hubin (jobob@qq.com). * <p> * 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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * 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.plugins; import java.lang.reflect.Proxy; import java.sql.Statement; import java.util.Properties; import org.apache.ibatis.executor.statement.StatementHandler; 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.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.toolkit.PluginUtils; import com.baomidou.mybatisplus.toolkit.SqlUtils; import com.baomidou.mybatisplus.toolkit.StringUtils; import com.baomidou.mybatisplus.toolkit.SystemClock; /** * <p> * 性能分析拦截器,用于输出每条 SQL 语句及其执行时间 * </p> * * @author hubin nieqiurong TaoYu * @Date 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 { /** * SQL 执行最大时长,超过自动停止运行,有助于发现问题。 */ private long maxTime = 0; private boolean format = false; 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; } try { statement.getClass().getDeclaredField("stmt"); statement = (Statement) SystemMetaObject.forObject(statement).getValue("stmt.statement"); } catch (Exception e) { // do nothing } String originalSql = statement.toString(); int index = originalSql.indexOf(':'); String sql = originalSql; if (index > 0) { sql = originalSql.substring(index + 1, originalSql.length()); } long start = SystemClock.now(); Object result = invocation.proceed(); long end = SystemClock.now(); long timing = end - start; String formatSql = SqlUtils.sqlFormat(sql, format); Object target = PluginUtils.realTarget(invocation.getTarget()); MetaObject metaObject = SystemMetaObject.forObject(target); MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); System.err.println(" Time:" + timing + " ms" + " - ID:" + ms.getId() + "\n Execute SQL:" + formatSql + "\n"); if (maxTime >= 1 && timing > maxTime) { throw new MybatisPlusException(" The SQL execution time is too large, please optimize ! "); } return result; } public Object plugin(Object target) { if (target instanceof StatementHandler) { return Plugin.wrap(target, this); } return target; } 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 void setMaxTime(long maxTime) { this.maxTime = maxTime; } public boolean isFormat() { return format; } public void setFormat(boolean format) { this.format = format; } }