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() 获取当前线程绑定的数据源标识。