spring boot+atomikos+mybatis+druid分布式事务实现

配置数据源

新建配置类DataSourceConfig:

public class DataSourceConfig {

    private static final String PRIMARY_MAPPER_BASE_PACKAGE = "io.github.yidasanqian.mapper.master";
    private static final String BUSINESS_MAPPER_BASE_PACKAGE = "io.github.yidasanqian.mapper.business";

    private static final String DATASOURCE_DRUID_PROPERTIES = "datasource/druid.properties";
    private static final String DATASOURCE_DRUID_PRIMARY_PROPERTIES = "datasource/druid-primary.properties";
    private static final String DATASOURCE_DRUID_BUSINESS_PROPERTIES = "datasource/druid-business.properties";

    private static final String CLASSPATH_MAPPER_XML = "classpath:mapper/*/*.xml";

    /**
     * druid 公共配置
     */
    private static Properties commonProperties;

    static {
        commonProperties = new Properties();
        InputStream in = DataSourceConfig.class.getClassLoader().getResourceAsStream(DATASOURCE_DRUID_PROPERTIES);
        try {
            commonProperties.load(in);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private Properties loadDruidProperties(String path) throws IOException {
        Properties properties = new Properties();
        InputStream in = getClass().getClassLoader().getResourceAsStream(path);
        properties.load(in);
        for (Map.Entry<Object, Object> entry : commonProperties.entrySet()) {
            properties.setProperty(entry.getKey().toString(), entry.getValue().toString());
        }
        return properties;
    }

    /**
     * 设置数据源
     *
     * @return
     * @throws IOException
     */
    @Primary
    @Bean
    public AtomikosDataSourceBean primaryDataSource() throws IOException {
        return getAtomikosDataSourceBean(DATASOURCE_DRUID_PRIMARY_PROPERTIES);
    }


    @Bean
    public AtomikosDataSourceBean businessDataSource() throws IOException {
        return getAtomikosDataSourceBean(DATASOURCE_DRUID_BUSINESS_PROPERTIES);
    }

    private AtomikosDataSourceBean getAtomikosDataSourceBean(String dataSourceProperties) throws IOException {
        Properties properties = loadDruidProperties(dataSourceProperties);
        AtomikosDataSourceBean dataSourceBean = new AtomikosDataSourceBean();
        // 配置DruidXADataSource
        DruidXADataSource xaDataSource = new DruidXADataSource();
        xaDataSource.configFromPropety(properties);
        // 设置置AtomikosDataSourceBean XADataSource
        dataSourceBean.setXaDataSource(xaDataSource);
        return dataSourceBean;
    }

    /**
     * 设置{@link SqlSessionFactoryBean}的数据源
     * @param primaryDataSource 主数据源
     * @return
     */
    @Primary
    @Bean
    public SqlSessionFactoryBean primarySqlSessionFactoryBean(@Qualifier("primaryDataSource") AtomikosDataSourceBean primaryDataSource) {
        return getSqlSessionFactoryBean(primaryDataSource);
    }

    @Bean
    public SqlSessionFactoryBean businessSqlSessionFactoryBean(@Qualifier("businessDataSource") AtomikosDataSourceBean businessDataSource) {
        return getSqlSessionFactoryBean(businessDataSource);
    }

    private SqlSessionFactoryBean getSqlSessionFactoryBean(AtomikosDataSourceBean dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            sqlSessionFactoryBean.setMapperLocations(resolver.getResources(CLASSPATH_MAPPER_XML));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return sqlSessionFactoryBean;
    }

    /**
     * 搜索{@link DataSourceConfig#PRIMARY_MAPPER_BASE_PACKAGE} 包下的Mapper接口,并且将这些接口
     * 交由{@link MapperScannerConfigurer#sqlSessionFactoryBeanName} 属性设置的SqlSessionFactoryBean管理
     * @return
     */
    @Bean
    public MapperScannerConfigurer primaryMapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage(PRIMARY_MAPPER_BASE_PACKAGE);
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("primarySqlSessionFactoryBean");
        return mapperScannerConfigurer;
    }

    /**
     * 搜索{@link DataSourceConfig#BUSINESS_MAPPER_BASE_PACKAGE} 包下的Mapper接口,并且将这些接口
     * 交由{@link MapperScannerConfigurer#sqlSessionFactoryBeanName} 属性设置的SqlSessionFactoryBean管理
     * @return
     */
    @Bean
    public MapperScannerConfigurer businessMapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage(BUSINESS_MAPPER_BASE_PACKAGE);
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("businessSqlSessionFactoryBean");
        return mapperScannerConfigurer;
    }
}

代码上都有注释,如有疑问,评论指出。

代码实现

结构:

这里写图片描述

两个Mapper接口定义一样的save方法

service实现类DemoServiceImpl

@Transactional(rollbackFor = Exception.class)
@Service
public class DemoServiceImpl implements DemoService {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Resource
    private MasterDemoMapper masterDemoMapper;

    @Resource
    private BusinessDemoMapper businessDemoMapper;

    /**
     * 正常测试分布式事务
     *
     * @return
     * @throws Exception
     */
    @Override
    public int save() throws Exception {
        log.info("save");
        Demo dsDemo = new Demo();
        dsDemo.setName("xa事务测试");
        int row = masterDemoMapper.save(dsDemo);
        log.info("保存之后");
        Demo dsDemo1 = new Demo();
        dsDemo1.setName("xa事务测试2");
        int row2 = businessDemoMapper.save(dsDemo1);
        return row + row2;
    }

    /**
     * 测试分布式事务回滚
     * @return
     * @throws Exception
     */
    @Override
    public int save2() throws Exception {
        log.info("save2");
        Demo dsDemo = new Demo();
        dsDemo.setName("xa事务回滚测试");
        int row = masterDemoMapper.save(dsDemo);
        log.info("保存之后异常");
        int a = 1 / 0;

        Demo dsDemo1 = new Demo();
        dsDemo1.setName("xa事务回滚测试2");
        int row2 = businessDemoMapper.save(dsDemo1);
        return row + row2;
    }
}

DemoController:

@RestController
public class DemoController {

    @Resource
    private DemoService dsService;

    @RequestMapping("/testXaDatasource")
    public String testXaDatasource() {
        int result = 0;
        try {
            result = dsService.save();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return String.valueOf(result);
    }

    @RequestMapping("/testXaDatasource2")
    public String testXaDatasource2() {
        int result = 0;
        try {
            result = dsService.save2();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return String.valueOf(result);
    }
}

访问http://localhost:8080/testXaDatasource返回2,表明多数据源及分布式事务可用。

访问http://localhost:8080/testXaDatasource2返回0,表明分布式事务回滚可用

源码地址

https://gitee.com/yidasanqian/spring-boot-distributed-transaction-demo.git

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值