有些应用一般会读写分离. 故对于程序而言涉及到多个数据源. 这里将多个数据源切换的功能做了下封装

实现

  1. 定义多个数据源 并分配一个 key 与之对应.
  2. 线程上下文存储当前 数据源的 key
  3. 实现 AbstractRoutingDataSource 重写 determineCurrentLookupKey 方法 为从线程上下文中取. 并注册到spring 容器
  4. 方便起见,定义一个注解 @DataSource 放在 mybatis mapper 方法签名上用于标识 用哪个数据源
  5. 新增 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) {
        //
    }
}

niguanwo
1 声望0 粉丝

这里当做笔记本.


引用和评论

0 条评论