spring boot应用,通常我们在进行数据管理时,只操作一个数据源的表,需要开启事务管理,只需要在服务启动类增加@EnableTransactionManagement注解,在需要事务控制的方法增加@Transactional注解即可。
即便是多数据源切换情况下,在需要事务控制的方法只操作一个数据源,也可以满足。
但如果在需要事务控制的方法里,同时操作多个数据源的表,这时候仅仅是上述两个注解,不能保证事务的一致性(这是分布式事务的范畴)。比如,我要往A数据源的表插如一条记录,同时更新B数据源的表,并且需要进行事务控制,该怎么处理?
首先我们要理解,什么是分布式事务。分布式事务,是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上,分布式事务需要保证这些节点操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。
针对上面的问题,我们使用atomikos+jta实现分布式事务统一管理,这在spring boot应用里非常简单,直接看示例代码:
1.首先引入atomikos依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> </dependency>
2.dao层我们使用spring jdbc来实现,所以还需要引入spring-jdbc依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <exclusions> <exclusion> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </exclusion> </exclusions> </dependency>
注意,这里使用atomikos,所以不需要HikariCP连接池。
3.加入mysql的jdbc驱动:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
4.增加数据源的java配置:
import java.sql.SQLException; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import com.atomikos.jdbc.AtomikosDataSourceBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; @Configuration public class DatasourceConfiguration { public static final String XA_DS1 = "xaDS01"; public static final String XA_DS2 = "xaDS02"; public static final String ATOMIKOS_DS1 = "atomikosDS01"; public static final String ATOMIKOS_DS2 = "atomikosDS02"; public static final String JDBC_TEMPLATE_DS1 = "jdbcTemplateDS01"; public static final String JDBC_TEMPLATE_DS2 = "jdbcTemplateDS02"; @Bean(name=XA_DS1) @ConfigurationProperties(prefix = "hzwei.datasource.ds1.xa") public MysqlXADataSource xaDS01() throws SQLException { MysqlXADataSource xaDataSource = new MysqlXADataSource(); xaDataSource.setPinGlobalTxToPhysicalConnection(true); xaDataSource.setPinGlobalTxToPhysicalConnection(true); return xaDataSource; } @Bean(name=XA_DS2) @ConfigurationProperties(prefix = "hzwei.datasource.ds2.xa") public MysqlXADataSource xaDS02() throws SQLException { MysqlXADataSource xaDataSource = new MysqlXADataSource(); xaDataSource.setPinGlobalTxToPhysicalConnection(true); xaDataSource.setPinGlobalTxToPhysicalConnection(true); return xaDataSource; } @Bean(name=ATOMIKOS_DS1) @ConfigurationProperties(prefix = "hzwei.datasource.xa") public AtomikosDataSourceBean atomikosDS01(@Qualifier(XA_DS1) MysqlXADataSource dataSource) throws SQLException { AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean(); atomikosDataSourceBean.setXaDataSource(dataSource); atomikosDataSourceBean.setUniqueResourceName(ATOMIKOS_DS1); return atomikosDataSourceBean; } @Bean(name=ATOMIKOS_DS2) @ConfigurationProperties(prefix = "hzwei.datasource.xa") public AtomikosDataSourceBean atomikosDS02(@Qualifier(XA_DS2) MysqlXADataSource dataSource) throws SQLException { AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean(); atomikosDataSourceBean.setXaDataSource(dataSource); atomikosDataSourceBean.setUniqueResourceName(ATOMIKOS_DS2); return atomikosDataSourceBean; } @Bean(name = JDBC_TEMPLATE_DS1) public JdbcTemplate jdbcTemplateDS01(@Qualifier(ATOMIKOS_DS1) DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean(name = JDBC_TEMPLATE_DS2) public JdbcTemplate jdbcTemplateDS02(@Qualifier(ATOMIKOS_DS2) DataSource dataSource) { return new JdbcTemplate(dataSource); } }
5.application.properties增加数据源配置项:
hzwei.datasource.ds1.xa.url=jdbc:mysql://localhost:3306/test_01?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull hzwei.datasource.ds1.xa.user=root hzwei.datasource.ds1.xa.password=root123 hzwei.datasource.ds2.xa.url=jdbc:mysql://localhost:3306/test_02?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true hzwei.datasource.ds2.xa.user=root hzwei.datasource.ds2.xa.password=root123 hzwei.datasource.xa.min-pool-size=5 hzwei.datasource.xa.max-pool-size=25 hzwei.datasource.xa.max-lifetime=20000 hzwei.datasource.xa.borrow-connection-timeout=30 hzwei.datasource.xa.login-timeout=30 hzwei.datasource.xa.maintenance-interval=60 hzwei.datasource.xa.max-idle-time=60
6.dao层:
@Repository("userDao1") public class UserDao1 implements IUserDao{ @Resource(name = DatasourceConfiguration.JDBC_TEMPLATE_DS1) private JdbcTemplate jdbcTemplate; @Override public void saveUser(User user){ //....saveUser... } } ***************************************************** @Repository("userDao2") public class UserDao2 implements IUserDao{ @Resource(name = DatasourceConfiguration.JDBC_TEMPLATE_DS2) private JdbcTemplate jdbcTemplate; @Override public void saveUser(User user){ //....saveUser... } }
7.service层:
@Service public class UserServiceImpl implements IUserService{ @Resource(name = "userDao1") private IUserDao userDao1; @Resource(name = "userDao2") private IUserDao userDao2; @Override @Transactional public void saveUser(User user){ userDao1.saveuser(user); userDao2.saveuser(user); //throw new RuntimeException("test rollback"); } }
PS:最后要注意一点,由于我们这里配置的是分布式数据源,没有配置默认数据源,所以需要在启动程序禁止DataSourceAutoConfiguration的初始化:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
当然,你也可以指定一个数据源增加@Primary注解(仅能注解一个数据源),这样不需要exclude = {DataSourceAutoConfiguration.class}。
否则,应用启动会报错。
相关推荐
Spring boot+Atomikos+JTA+Hibernate+MySQL实现分布式事务+多数据源,分别向两个不同的数据里面插入数据同时失败和成功,调用接口方式原理一样。
spring boot下学习mybatis+mysql使用jta对多数据源事务进行整合
本用例基于 Spring Boot + Druid + Mybatis 配置多数据源,并采用 JTA 实现分布式事务。
博客上有很多类似的,很多都有点小错误。还是自己搭建测试的好用。resource中有sql,自己创建两个数据库导入sql,即可运行test测试
该文件是给什么都不会的小白,下载下来进行简单的配置就可以运行,可以到https://blog.csdn.net/qq_43314669/article/details/106733829 进行在线观看
springboot+Atomikos+jpa+mysql的JTA分布式事务实现,本案例涉及到2个数据库,预期结果,在同一个事务中,两个库的状态一致
同一个服务里面多个数据源事务事务一致性
同一个服务里面多个数据源事务事务一致性
同一个服务里面多个数据源事务事务一致性
springboot+sqlserver+主从读写分离 使用springaop实现,增加jta多数据源分布式事务管理
1课程的介绍 2数据库事务的介绍 3mysq|事务讲解 4mysq|-JDBC事务讲解1 5mysqI-JDBC事务讲解2 6搭建一个spring-boot项目 7idea插件easycode 8spring-boot标签事务 ...11spring-boot jta多数据源事务实例
使用JTA处理分布式事务 i. 32.1. 使用一个Atomikos事务管理器 ii. 32.2. 使用一个Bitronix事务管理器 iii. 32.3. 使用一个J2EE管理的事务管理器 iv. 32.4. 混合XA和non-XA的JMS连接 v. 32.5. 支持可替代的内嵌事务...
分布式事务,多数据源事务全靠他.Cache:spring-cache. 统一接口,注解使用,simple,redis... 自动切换.Scheduler:quartz. 开源稳定,支持集群.自家:hsweb-commons :通用工具类hsweb-easy-orm :为动态表单设计的orm...
支持多数据源;支持读写分离、分库分表。J2eeFAST功能:1、用户管理:用户是系统操作者,该功能主要完成系统用户配置。2、部门管理:配置系统组织机构(公司、部门),树结构展现支持数据权限。3、岗位管理:配置...