有些应用一般会读写分离. 故对于程序而言涉及到多个数据源. 这里将多个数据源切换的功能做了下封装
实现
- 定义多个数据源 并分配一个 key 与之对应.
- 线程上下文存储当前 数据源的 key
- 实现 AbstractRoutingDataSource 重写 determineCurrentLookupKey 方法 为从线程上下文中取. 并注册到spring 容器
- 方便起见,定义一个注解 @DataSource 放在 mybatis mapper 方法签名上用于标识 用哪个数据源
- 新增 mybatis 插件(拦截器), 根据 @DataSource 动态指定所用数据源. 方法执行完ThreadLocal记得remove
// 初始化 多个数据源,并重写找 数据源 key 的方法为 从线程上下文中取
public class MultiRoutingDataSource extends AbstractRoutingDataSource {
public MultiRoutingDataSource(Object defaultDataSource, Map<Object, Object> dataSources) {
setDefaultTargetDataSource(defaultDataSource);
Map<Object, Object> dses = Maps.newHashMap(MultiDsHolder.defaultDsKey, defaultDataSource);
dses.putAll(dataSources);
setTargetDataSources(dses);
}
@Override
protected Object determineCurrentLookupKey() {
return MultiDsHolder.get();
}
}
// 现在拦截器, 动态指定数据源
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {
MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class})})
public class MultiDsPlugin implements Interceptor {
protected static final Logger logger = LoggerFactory.getLogger(MultiDsPlugin.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
DataSource annotation = invocation.getMethod().getAnnotation(DataSource.class);
if (annotation != null) {
String key = annotation.value();
MultiDsHolder.set(key);
} else {
//没配的话就用默认的
MultiDsHolder.set(MultiDsHolder.defaultDsKey);
}
Object rst = null;
try {
rst = invocation.proceed();
} catch (Exception e) {
logger.error("mybatis 执行出错:", e);
} finally {
MultiDsHolder.remove();
}
return rst;
}
@Override
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties properties) {
//
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。