配置数据源

新建配置类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

GitHub 加速计划 / druid / druid
3
3
下载
阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池
最近提交(Master分支:5 个月前 )
f95350b3 - 4 小时前
cb6f3ac7 - 2 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐