MyBatis 拦截器的应用之动态数据源读写控制

背景是在 SpringBoot 项目中使用了 dynamic-datasource 实现动态动态数据源,为了防止在生产库中执行修改操作,我希望限制只当当前数据源为指定值时,才能进行更新操作,其他数据源仅可读。

可创建如下 MyBatis 拦截器来实现:

@Intercepts({
    @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
@Component
public class DataSourceWriteInterceptor implements Interceptor {

    // 允许执行写操作的数据源名称(可改写为支持配置)
    private final Set<String> allowedWriteDataSources = new HashSet<>(Arrays.asList("master"));

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取当前数据源标识
        String currentDs = DynamicDataSourceContextHolder.peek();

        // 检查是否为 SELECT 操作
        MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
        if (ms.getSqlCommandType() == SqlCommandType.SELECT) {
            return invocation.proceed();
        }

        // 验证写权限
        if (!allowedWriteDataSources.contains(currentDs)) {
            throw new IllegalStateException("数据源[" + currentDs + "]禁止写操作");
        }

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {}
}

核心是使用 DynamicDataSourceContextHolder.peek() 获取当前线程绑定的数据源标识。

推荐阅读:MyBatis 拦截器使用及原理动态数据源 @DS 注解源码解析

posted @ 2025-03-18 22:52  Higurashi-kagome  阅读(43)  评论(0)    收藏  举报