Mybatis输出完整Sql - Interceptor ...
@Intercepts(
{
@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}),
@Signature(type = Executor.class, method = "update"
, args = {MappedStatement.class, Object.class}),
}
)
@Slf4j
public class MybatisSqlLogInterceptor implements Interceptor {
/**
* 当语句中某个参数值过长,超过配置的阈值,会显示参数开头及下面的省略号
*/
private static final String LONG_PARAM_DESC = ".....";
@Setter
Supplier<Long> slowSqlThreshold = () -> 1000L; // NOSONAR
@Setter
Supplier<Long> paramLengthLogLimit = () -> 1024L; // NOSONAR
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object proceed;
try {
long start = System.currentTimeMillis();
proceed = invocation.proceed();
long costTime = System.currentTimeMillis() - start;
if (costTime > slowSqlThreshold.get()) {
SqlDetail sqlDetail = getSqlDetail(invocation);
log.info("executeSql: {} pararm:[{}] methodName:[{}] rowsNum:[{}] elapsedTime:{}ms"
, sqlDetail.getSql()
, sqlDetail.getParam()
, sqlDetail.getMethodName()
, getReturnRows(proceed)
, costTime);
}
} catch (Exception exception) {
SqlDetail sqlDetail = getSqlDetail(invocation);
log.error("executeSql: {} pararm:[{}] methodName:[{}] "
, sqlDetail.getSql()
, sqlDetail.getParam()
, sqlDetail.getMethodName()
, exception);
throw exception;
}
return proceed;
}
/**
* 获取SQL语句和参数
*/
@Nullable
private SqlDetail getSqlDetail(Invocation invocation) {
SqlDetail sqlDetail = new SqlDetail();
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
if (null != mappedStatement) {
String methodLocate = mappedStatement.getId();
sqlDetail.setMethodName(getMethodName(methodLocate, '.'));
}
Object parameter = null;
if (invocation.getArgs().length > 1) {
parameter = invocation.getArgs()[1];
}
//获取参数
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
sqlDetail.setSql(boundSql.getSql());
Configuration configuration = mappedStatement.getConfiguration();
Object parameterObject = boundSql.getParameterObject();
StringBuffer sqlParam = new StringBuffer(128);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
//参数遍历拼接
if (parameterObject != null) {
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
// 如果根据parameterObject.getClass()可以找到对应的类型,则替换
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
String param = ConvertUtil.toString(parameterObject);
sqlParam.append(param.length() > paramLengthLogLimit.get()
? param.substring(0, paramLengthLogLimit.get().intValue()) + LONG_PARAM_DESC : param);
sqlDetail.setParam(sqlParam.toString());
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
String param = ConvertUtil.toString(metaObject.getValue(propertyName));
sqlParam.append(param.length() > paramLengthLogLimit.get()
? param.substring(0, paramLengthLogLimit.get().intValue()) + LONG_PARAM_DESC
: param)
.append(',');
}
if (boundSql.hasAdditionalParameter(propertyName)) {
String param = ConvertUtil.toString(boundSql.getAdditionalParameter(propertyName));
sqlParam.append(param.length() > paramLengthLogLimit.get() ?
param.substring(0, paramLengthLogLimit.get().intValue()) + LONG_PARAM_DESC
: param)
.append(',');
}
}
}
if (sqlParam.length() > 0) {
sqlDetail.setParam(sqlParam.deleteCharAt(sqlParam.length() - 1).toString());
}
}
return sqlDetail;
}
private Integer getReturnRows(Object proceed) {
if (proceed instanceof Collection) {
return ((Collection<?>) proceed).size();
}
if (proceed instanceof Map) {
return ((Map) proceed).size();
}
if (proceed instanceof Integer) {
return (Integer) proceed;
}
return 0;
}
/**
* 生成MyBatis拦截器代理对象
**/
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
/**
* 设置插件属性
*/
@Override
public void setProperties(Properties properties) {
}
String getMethodName(String str, char separator) {
if (str == null || str.length() == 0) {
return str;
}
final int pos = str.lastIndexOf(separator);
if (pos == -1) {
return str;
}
final int secondPos = str.lastIndexOf(separator, pos - 1);
if (secondPos == -1) {
return str;
}
return str.substring(secondPos + 1);
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public static class SqlDetail {
private String sql;
private String param;
private String methodName;
}
}