本节我们主要去通过mybatis的拦截器去修改原始sql。对于pageHelper导致mybatis的拦截器不生效的问题可以去看之前的文章. 对于不生效这个东东我补充一点:其实我们自己的拦截器和pageHelper的冲突,导致失效的原因是我们和他们拦截type都是Executor。如果我们拦截的类型是StatementHandler,这样其实你配置了拦截器的先后顺序,最终也不会按照你配置的顺序执行。因为拦截 Executor 和 拦截 StatementHandler 就属于不同的拦截对象, 这两类的拦截器在整体执行的逻辑上是不同的,StatementHandler 属于 Executor 执行过程中的一个子过程。 所以这两种不同类别的插件在配置时,一定是先执行 Executor 的拦截器,然后才会轮到 StatementHandler。所以这种情况下配置拦截器的顺序就不重要了,在 MyBatis 逻辑上就已经控制了先后顺序(参考:github.com/pagehelper/…
mybatis的拦截器怎么写,其实网上有很多例子,我们直接贴上我们的代码吧。
import com.lang.oliver.service.context.LoginContext;
import com.lang.oliver.service.context.TraceContext;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.sql.Connection;
@Intercepts({@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class}
)})
public class AuditCDCLogInterceptor implements Interceptor {
private static Logger logger = LoggerFactory.getLogger(AuditCDCLogInterceptor.class);
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = statementHandler.getBoundSql();
this.modifySql(boundSql);
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
private void modifySql(BoundSql boundSql) {
try {
Long customerId = LoginContext.getLoginUserId();
String operatorId = customerId != null ? String.valueOf(customerId) : "unknown";
String updatedSql = String.format("/*@%s,%s@*/ %s", operatorId, TraceContext.getTraceId(), boundSql.getSql());
logger.debug("updatedSql: {}", updatedSql);
Field field = boundSql.getClass().getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, updatedSql);
} catch (Exception var6) {
logger.error("Failed modify sql", var6);
}
}
}
这种代码其实很简单,其实你可以上面添加一个自己的控制,比如我要不要开启sql拦截,或者说只是拦截部分的表,都可以基于他做一些修改的。 这里面的操作人id和链路的traceId是可以通过web端的调用进行透传过来的,如果你是用的dubbo可以基于dubbo的filter来做,如果是http的,可以通过Header透传过来。
好啦,本节就讲完了,整个项目的源码在: github.com/waterlang/a…