最近工作中在同一项目中用到了多数据源,虽然项目本身对多数据源的事务没有要求,甚至可以不使用事务。但是本着精益求精的原则,加上各种资料的查阅,终于实现了多数据源的XA(分布式事务)

项目框架

  • springboot2.0.x
  • springmvc
  • mybatis

对多数据源的mapper的处理

针对多个数据源,mapper通常有两种处理方式:一种是将各个数据源对应的mapper放置在不同的package中,通过配置各个对应的SqlSessionFactory来实例化各自的mapper;另一种是使用动态数据源,即在程序运行时,通过注解or函数动态的设置当前使用哪个数据源,而mapper本身是不知道自己会使用哪个数据源的

目前我使用的是前一种方案,毕竟这种方案各个mapper都很清楚的知道自己将会使用哪个数据源,第二种方案我目前还没使用的需求。

对于如何配置各个数据源对应不同的mapper,我会再后续的文章中阐述。本文着重阐述如何在springboot中配置XA

第一步,引入spring-boot-starterspring-boot-starter-jta-atomikos

     <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jta-atomikos</artifactId></dependency>

springboot中配置xa共需要配置两个东西,一个是支持xa的数据源,一个是基于xa的分布式事务管理器
因为在项目中我们已经引入了spring-boot-starter-jta-atomikos,它会自带一个支持xa的分布式事务管理器(此依赖还会自动创建一个支持xa的数据源,但是只能自动创建一个,而我们如果用xa的话,肯定是多数据源,所以这里感觉springboot的这个“默认”配置有点zz),因此我们只需要配置好多个数据源即可(必须是支持xa的数据源)

我们这里以两个数据源为例:
我们先构造一个数据源创建器

@Component
public class DataSourceConfig implements BeanClassLoaderAware{@SetterClassLoader beanClassLoader;protected XADataSource createXaDataSource(DataSourceProperties properties) {String className = properties.getXa().getDataSourceClassName();if (!StringUtils.hasLength(className)) {className = DatabaseDriver.fromJdbcUrl(properties.determineUrl()).getXaDataSourceClassName();}Assert.state(StringUtils.hasLength(className),"No XA DataSource class name specified");XADataSource dataSource = createXaDataSourceInstance(className);bindXaProperties(dataSource, properties);return dataSource;}private XADataSource createXaDataSourceInstance(String className) {try {Class<?> dataSourceClass = ClassUtils.forName(className, this.beanClassLoader);Object instance = BeanUtils.instantiateClass(dataSourceClass);Assert.isInstanceOf(XADataSource.class, instance);return (XADataSource) instance;}catch (Exception ex) {throw new IllegalStateException("Unable to create XADataSource instance from '" + className + "'");}}private void bindXaProperties(XADataSource target,DataSourceProperties dataSourceProperties) {Binder binder = new Binder(getBinderSource(dataSourceProperties));binder.bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(target));}private ConfigurationPropertySource getBinderSource(DataSourceProperties dataSourceProperties) {MapConfigurationPropertySource source = new MapConfigurationPropertySource();source.put("user", dataSourceProperties.determineUsername());source.put("password", dataSourceProperties.determinePassword());source.put("url", dataSourceProperties.determineUrl());source.putAll(dataSourceProperties.getXa().getProperties());ConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();aliases.addAliases("user", "username");return source.withAliases(aliases);}
}

这里思路是使用特定的配置文件(DataSourceProperties)来构建一个DataSource对象,这里有不少代码都参考的SpringBoot中XADataSourceAutoConfiguration.java的源码
然后我们构建两个数据源:
第一个数据源

 @Configurationpublic static class MybatisDbBConfigODS extends DataSourceConfig{@AutowiredXADataSourceWrapper wrapper;@Bean@Primary@ConfigurationProperties("spring.datasource.ods")public DataSourceProperties getDataSourceProperties() {return new DataSourceProperties();}@Bean@Primarypublic DataSource getDataSource() throws Exception {XADataSource xaDataSource = createXaDataSource(getDataSourceProperties());return this.wrapper.wrapDataSource(xaDataSource);}}

这里的思路是先将当前数据源需要的属性(例如用户名、密码、数据库连接地址等)加载到DataSourceProperties中,然后使用此对象来创建DataSource对象,注意这里的XADataSourceWrapper对象,它的作用是将XA数据源转化为普通的数据源。
第二个数据源的创建方法类似:

 @Configuration@MapperScan(basePackages = "com.xinbo.ods.dao.cdr", sqlSessionFactoryRef = "sqlSessionFactory4cdr", sqlSessionTemplateRef = "sqlSessionTemplate4cdr", annotationClass = Mapper.class)public static class MybatisDbBConfigCDR  extends DataSourceConfig{@AutowiredXADataSourceWrapper wrapper;@Bean("UNJi29SsAF19WVCkeKdt")@ConfigurationProperties("spring.datasource.cdr")public DataSourceProperties getDataSourceProperties() {return new DataSourceProperties();}@Bean("ahS54La6KNmWnchdQQil")public DataSource getDataSource4cdr() throws Exception {XADataSource xaDataSource = createXaDataSource(getDataSourceProperties());return this.wrapper.wrapDataSource(xaDataSource);}}

要注意的是,最好每个@Bean注解中使用唯一的名字,否则会和上的重名,然后出现问题
到这里所有的配置已经配置好了,然后我们使用事务时,只需要在需要的类或方法上加上@Transactional注解即可,当一个事务中同时操作多个数据库时,遇到异常会回滚对所有数据库的操作。

PS:对于springboot是如何创建支持XA的事务管理器TransactionManager的,如果有兴趣,可以参考这个类的源码:AtomikosJtaConfiguration.java

【SpringBoot2.0】基于Atomikos的多数据源分布式事务(XA)解决方案相关推荐

  1. SpringBoot+MyBatis(动态数据源/分布式事务XA(Atomikos))

    快速集成工具,欢迎打脸 说明 适用环境:SpringBoot / MyBatis / Atomickos  特性: 多数据源,动态切换 多数据源,XA分布式事务支持(需引入Atomickos) 仅支持 ...

  2. spring boot+Mybatis+mysql+atomikos+jta实现多数据源分布式事务

    spring boot+Mybatis+mysql+atomikos+jta实现多数据源分布式事务 1.导入相关依赖 2.配置相关application.properties 3.创建配置文件 4.创 ...

  3. springmvc atomikos mysql数据源_Spring多数据源分布式事务管理/springmvc+spring+atomikos[jta]+druid+mybatis...

    项目进行读写分离及分库分表,在一个业务中,在一个事务中处理时候将切换多个数据源,需要保证同一事务多个数据源数据的一致性.此处使用atomikos来实现:最后附源码: 1:spring3.0之后不再支持 ...

  4. dremio连接mysql_一种基于dremio实现跨数据源分布式查询系统和方法_2018108444691_说明书_专利查询_专利网_钻瓜专利网...

    a.给选择出的最优sql配置一个sqlid和sql模板: b.sql模板会预留sql参数: c.用户通过sqlid和参数调用查询接口: d.查询接口使用模板生成dremio的sql: e.通过drem ...

  5. Spring中使用atomikos+druid实现经典分布式事务

    经典分布式事务,是相对互联网中的柔性分布式事务而言,其特性为ACID原则,包括原子性(Atomictiy).一致性(Consistency).隔离性(Isolation).持久性(Durabilit) ...

  6. Spring Boot之基于Dubbo和Seata的分布式事务解决方案

    转载自 Spring Boot之基于Dubbo和Seata的分布式事务解决方案 1. 分布式事务初探 一般来说,目前市面上的数据库都支持本地事务,也就是在你的应用程序中,在一个数据库连接下的操作,可以 ...

  7. 基于可靠消息方案的分布式事务(四):接入Lottor服务

    在上一篇文章中,通过Lottor Sample介绍了快速体验分布式事务Lottor.本文将会介绍如何将微服务中的生产方和消费方服务接入Lottor. 场景描述 生产方:User服务 消费方:Auth服 ...

  8. base cap 分布式_干货分享:基于本地消息表的分布式事务解决方案总结

    前段时间学习了分布式事务的几种方案,下面主要总结下基于本地消息表实现可靠消息最终一致性的分布式事务方案. 1,什么是分布式事务? 在传统架构中往往是一个单体架构,一个系统就对应一个war包,然后这个系 ...

  9. 手写基于Spring Cloud的TCC分布式事务框架

    如何简单实现TCC分布式事务框架 最近听到很多其他公司的小伙伴谈分布式事务的问题,各种业务场景都有,可能就是这两年很多公司都在往微服务发展,现在各个子系统都拆分.建设的差不多了,实现了模块化开发,但是 ...

最新文章

  1. 我是IT小小鸟 读书笔记
  2. python哨兵循环_Python:deadloop之非模态交互界面(模态循环)(哨兵循环)
  3. 成功数据恢复一例LINUX EXT3 下误删除ORACLE数据库
  4. [转载]Java并发编程:深入剖析ThreadLocal
  5. java中的char类型所占空间
  6. php 应用时间,PHP 日期与时间
  7. 数据挖掘技术有哪几种
  8. android-listview 优化 viewHolder(节点缓存池)
  9. HtmlHelper用法大全(下)
  10. 大型企业中复杂数据库存储过程的修改方法:7步法教你高效完成任务
  11. 量化交易 第三课 数据获取接口
  12. 短视频剪辑怎么自学?短视频剪辑的教程分享
  13. 用样本推断整体,中心极限定理及其一些前提条件
  14. Spring事务管理的总结
  15. Autofac程序集注入
  16. 状态空间方程的能控性与能观性判断
  17. python输出大字号汉字_Python print 玩转点阵字
  18. 并发-MESI缓存一直协议详解
  19. First, rewinding head to replay your work on top of it...
  20. php Memcache/Memcached操作手册

热门文章

  1. Qt解决资源文件中添加图片,对应控件不显示图片的问题
  2. python好学吗 老程序员-学习python,难道是为了当一名苦逼的程序员吗?
  3. 多御浏览器新出的手机版本有什么功能?
  4. java eclipse生成apk,将Eclipse Android项目打包成APK文件
  5. 操作系统介绍(按发展顺序)人工操作方式、单道批处理系统、多道批处理系统、分时系统、实时系统、微机操作系统
  6. [JavaScript]只需一行代码,轻松搞定快捷留言-V2升级版javascript
  7. 2019全国大学生信息安全竞赛 web JustSoso(parse_url解析漏洞+序列化)
  8. KDD 2020(五) | 基于多源异构信息整合的视频标题生成模型(作者带你读论文)...
  9. ValueError: The list of inputs passed to the model is redundant. All inputs should only appear once.
  10. 解析人工智能时代蕴含的人文主义精神