基于CDC做全链路数据审计系统-sql改写(三)

本节我们主要去通过mybatis的拦截器去修改原始sql。对于pageHelper导致mybatis的拦截器不生效的问题可以去看之前的文章(https://www.jianshu.com/p/8dc9f8a4cce9)。
对于不生效这个东东我补充一点:其实我们自己的拦截器和pageHelper的冲突,导致失效的原因是我们和他们拦截type都是Executor。如果我们拦截的类型是StatementHandler,这样其实你配置了拦截器的先后顺序,最终也不会按照你配置的顺序执行。因为拦截 Executor 和 拦截 StatementHandler 就属于不同的拦截对象, 这两类的拦截器在整体执行的逻辑上是不同的,StatementHandler 属于 Executor 执行过程中的一个子过程。 所以这两种不同类别的插件在配置时,一定是先执行 Executor 的拦截器,然后才会轮到 StatementHandler。所以这种情况下配置拦截器的顺序就不重要了,在 MyBatis 逻辑上就已经控制了先后顺序(参考:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Interceptor.md)。

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透传过来。

好啦,本节就讲完了,整个项目的源码在:
https://github.com/waterlang/audit-system

你可能感兴趣的:(基于CDC做全链路数据审计系统-sql改写(三))