spring中动态数据源切换失效问题剖析

我们在使用spring中动态数据源的时候,往往在业务代码中需要指定数据源,在进行业务操作的时候就会去指定的数据源操作数据:代码如下

数据源,两个数据源,ds1,ds2:

@Bean
    public DataSource dynamicDataSource() {

        Map<Object, Object> targetDataSources = new HashMap<>();
        ComboPooledDataSource ds1 = getDs1();
        targetDataSources.put("ds1", ds1);
        targetDataSources.put("ds2", getDs2());
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(ds1);
        return dynamicDataSource;
    }

业务代码切换数据源代码如下:

    @TargetSource("ds1")
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void transation(ConsultConfigArea area, ZgGoods zgGoods) {
        areaService.addArea(area);
        goodsService.addGoods(zgGoods);
    }

    @TargetSource("ds2")
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public int addArea(ConsultConfigArea area) {
        int i = commonMapper.addArea(area);
        return i;
    }


    @TargetSource("ds2")
    @Transactional
    @Override
    public void addGoods(ZgGoods zgGoods) {
        int i = commonMapper.addGood(zgGoods);
    }

我们的意图是,areaService.addArea(area);需要切换到ds2数据源。

测试结论:areaService.addArea(area);还是使用的ds1数据源连接对象,也就是前面那个事务的数据源连接对象。也就是说@TargetSource("ds2")注解失效了。

为什么会这样呢?

因为spring的事务传播属性导致的,前面那个  transation 方法已经有事务了,而transation方法下面的addArea方法事务传播属性是  propagation = Propagation.REQUIRED  这个传播属性就决定了addArea方法还是使用的 transation 方法的数据源连接对象,所以当执行到addArea的时候根本就不存在创建新的连接对象的可能

由于addArea采用的是 Propagation.REQUIRED传播属性,就不存在事务的挂起和doBegin操作,还是沿用的前面方法的数据库连接对象,所以这时候是没有从数据库连接池里面拿连接的。ok,看看doBegin方法:

扫描二维码关注公众号,回复: 14318267 查看本文章

只有走到doBegin方法时,spring才会从连接池对象中拿连接对象,而现在是没走到doBegin方法中来,所以addArea方法还是沿用的之前的连接对象,所以这里的@TargetSource("ds2")注解其实是没起作用的。

OK,希望得到帮助的同学,点个赞,谢谢

史上最深最全spring源码教程 - 网易云课堂

猜你喜欢

转载自blog.csdn.net/luoyang_java/article/details/104000609