【java多数据源连接】SpringBoot+MyBatis同一项目连接MySQL与SQLServer数据库,多数据源事务管理(三)

连接不同数据库,事务管理与细节

本文章有三篇:
第一篇:不使用数据库池连接多个数据库;
第二篇:使用数据库池连接多个数据库;
第三篇为 使用连接多个数据库后事务管理与细节;

gitee源码地址:多数据源事务管理 https://gitee.com/jack_of_disco/multiple-data-sources/tree/transactional-management
github源码地址:github多数据源事务管理 https://github.com/Crazy-GrowUp/multiple-data-sources/tree/transactional-management

在这里讨论一个方法中同时操作两个数据源,方法报错后两个数据源的数据是否会回滚

MySqlConfig.java

    @Bean(name = "mysqlTransactionManager")
    @Primary //(重要)配置mysql为主要(默认)事务管理器
    public DataSourceTransactionManager mysqlTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
  1. 全部回滚,使用手动控制事务提交。
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String testMyAndMS5() {
        // 下面的语句报错,但是当前的事务管理器是默认的(MySQL事务管理器)
        // 发送报错的位置在addTableUser方法内部,而addTableUser方法增加了MS事务管理器,所以MS可以回滚
        // 然后错误往上抛,testMyAndMS5()方法也触发异常,MySQL插入也回滚。
        // 此时两个数据库的插入在出现异常时,都可以回滚
        // 总结:不同的数据库操作,不要放在同一个方法内,否则无法回滚;建议同一个的数据库操作写一个方法,然后指定对应事务管理器
        User user = new User();
        user.setId(new Date().getTime());
        user.setName("小红6");
        user.setAge(226);
        UserTable userTable = new UserTable();
        userTable.setName("小铁6");
        userTable.setAge(316);
        userMapper.addUser(user);
        //报错
        this.addTableUser(userTable);
        return "OK";
    }

    public Integer addTableUser(UserTable userTable) {
        // 手动控制事务
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setName("myTransaction");
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = sqlserverTransactionManager.getTransaction(def);

        Integer i1;
        try {
            i1 = userTableMapper.addMsUser(userTable);
            int i = 1 / 0;
            sqlserverTransactionManager.commit(status);
        } catch (Exception e) {
            sqlserverTransactionManager.rollback(status);
            // 再次把错误抛给外面
            throw e;
        }
        return i1;
    }
  1. 只有 @Transactional 中的事务管理器的数据回滚
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String testMyAndMS2() {
        // 下面的语句报错,但是当前的事务管理器是默认的(MySQL事务管理器)
        // 发送报错时,MS的插入还没有执行,所有可以回滚成功
        User user = new User();
        user.setId(new Date().getTime());
        user.setName("小红2");
        user.setAge(222);
        UserTable userTable = new UserTable();
        userTable.setName("小铁2");
        userTable.setAge(312);
        userMapper.addUser(user);
        //报错
        int i = 1 / 0;
        userTableMapper.addMsUser(userTable);
        return "OK";
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String testMyAndMS3() {
        // 下面的语句报错,但是当前的事务管理器是默认的(MySQL事务管理器)
        // 发送报错时,MS的插入已经执行,MS无法回滚
        User user = new User();
        user.setId(new Date().getTime());
        user.setName("小红3");
        user.setAge(223);
        UserTable userTable = new UserTable();
        userTable.setName("小铁3");
        userTable.setAge(313);
        userTableMapper.addMsUser(userTable);
        //报错
        int i = 1 / 0;
        userMapper.addUser(user);

        return "OK";
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String testMyAndMS4() {
        // 下面的语句报错,但是当前的事务管理器是默认的(MySQL事务管理器)
        // 发送报错时,MS的插入已经执行,所有只有MySQL回滚成功,MS无法回滚
        User user = new User();
        user.setId(new Date().getTime());
        user.setName("小红4");
        user.setAge(224);
        UserTable userTable = new UserTable();
        userTable.setName("小铁4");
        userTable.setAge(314);
        userMapper.addUser(user);

        userTableMapper.addMsUser(userTable);
        //报错
        int i = 1 / 0;
        return "OK";
    }

对于多事务管理,还有一个 Seata 分布式事务管理框架,里面包含了 AT模式、TCC模式、Saga模式、XA模式。

你可能感兴趣的:(技术难题解决,方法使用,java,数据库,spring,boot,缓存,mysql,sqlserver,mybatis)