MyBatis拦截器获取SQL执行时间

拦截器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package com;

import com.baomidou.mybatisplus.toolkit.SqlUtils;
import com.baomidou.mybatisplus.toolkit.StringUtils;
import com.baomidou.mybatisplus.toolkit.SystemClock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.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 java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

/**
* @author
* @since 2021-09-24 10:59
**/
@Intercepts({
@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class }),
@Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class OrderPerformanceInterceptor implements Interceptor {

private static final Logger logger = LoggerFactory.getLogger(OrderPerformanceInterceptor.class);
/**
* SQL 执行最大时长,超过自动停止运行,有助于发现问题。
*/
private long maxTime = 0;

private boolean format = false;

public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object parameterObject = null;
if (invocation.getArgs().length > 1) {
parameterObject = invocation.getArgs()[1];
}

String statementId = mappedStatement.getId();
BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
Configuration configuration = mappedStatement.getConfiguration();
String sql = SqlUtils.sqlFormat(boundSql.getSql(), format);

List<String> params = getParams(boundSql, parameterObject, configuration);

long start = SystemClock.now();
Object result = invocation.proceed();
long end = SystemClock.now();
long timing = end - start;
if (sql.toLowerCase(Locale.ROOT).trim().startsWith("select")) {
logger.info("Time:{} ms - ID:{} SQL Params:{} Execute SQL:{}", timing, statementId, params.toString(), sql);
}else {
logger.info("Time:{} ms - ID:{} SQL Params:{} Execute SQL:{} result:{}", timing, statementId, params.toString(), sql, result);
}
return result;
}

public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
}
return target;
}

public void setProperties(Properties prop) {
// TODO
}

private List<String> getParams(BoundSql boundSql, Object parameterObject, Configuration configuration) {
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
List<String> params = new ArrayList<String>();
if (parameterMappings != null) {
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);
}
params.add(StringUtils.sqlParam(value));
}
}
}
return params;
}

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;
}
}

配置拦截器

1
2
3
4
5
6
7
8
9
10
11
<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.OrderPerformanceInterceptor"/>
</array>
</property>
</bean>