SpringBoot+JTA+Mybatis
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源。这时候就要管理多数据源事务。
什么是jta:https://www.ibm.com/developerworks/cn/java/j-lo-jta/
pom.xml
注意这里的druid用1.1.9
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>1.1.1</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.1.9</version>
- </dependency>
- <!-- JPA -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jta-atomikos</artifactId>
- </dependency>
配置第一个数据源
- import com.alibaba.druid.pool.xa.DruidXADataSource;
- import com.atomikos.icatch.jta.UserTransactionImp;
- import com.atomikos.icatch.jta.UserTransactionManager;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.spring.SqlSessionFactoryBean;
- import org.mybatis.spring.annotation.MapperScan;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.Primary;
- import org.springframework.transaction.jta.JtaTransactionManager;
- import javax.sql.DataSource;
- import javax.transaction.UserTransaction;
-
-
- @Configuration
- // // 扫描 Mapper 接口并容器管理
- @MapperScan(value ="mapper所在包路径" ,sqlSessionFactoryRef = "moviesSqlSessionFactory")
- public class MoviesDataSourceConfig {
-
-
- @Bean(name = "moviesDataSource")
- @Primary
- public DataSource masterDataSource() {
- DruidXADataSource druidXADataSource = new DruidXADataSource();
- druidXADataSource.setUrl("jdbc:mysql://localhost:3306/movies?useUnicode=true&characterEncoding=UTF8&useSSL=false");
- druidXADataSource.setUsername("root");
- druidXADataSource.setPassword("");
-
- AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
- atomikosDataSourceBean.setXaDataSource(druidXADataSource);
- atomikosDataSourceBean.setUniqueResourceName("moviesDataSource");
- atomikosDataSourceBean.setPoolSize(5);
-
- return atomikosDataSourceBean;
- }
-
- /*
- * 使用这个来做总事务 后面的数据源就不用设置事务了
- * */
- @Bean(name = "transactionManager")
- @Primary
- public JtaTransactionManager regTransactionManager () {
- UserTransactionManager userTransactionManager = new UserTransactionManager();
- UserTransaction userTransaction = new UserTransactionImp();
- return new JtaTransactionManager(userTransaction, userTransactionManager);
- }
-
- @Bean(name = "moviesSqlSessionFactory")
- @Primary
- public SqlSessionFactory masterSqlSessionFactory(@Qualifier("moviesDataSource") DataSource masterDataSource)
- throws Exception {
- final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
- sessionFactory.setDataSource(masterDataSource);
- return sessionFactory.getObject();
- }
-
-
-
- }
注意:不管有多少个数据源只要配置一个 JtaTransactionManager。
还有 DataSource里用的是DruidXADataSource ,而后注册到AtomikosDataSourceBean并且返回。
配置第二个数据源
- import com.alibaba.druid.pool.xa.DruidXADataSource;
-
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.spring.SqlSessionFactoryBean;
- import org.mybatis.spring.annotation.MapperScan;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- import javax.sql.DataSource;
-
- @Configuration
- // // 扫描 Mapper接口
- @MapperScan(value ="com.sunsharing.mapper" ,sqlSessionFactoryRef = "teacherSqlSessionFactory")
- public class TeacherDataSourceConfig {
-
-
- @Bean(name = "teacherDataSource")
- public DataSource masterDataSource() {
- DruidXADataSource druidXADataSource = new DruidXADataSource();
- druidXADataSource.setUrl("jdbc:mysql://localhost:3306/reactstu?useUnicode=true&characterEncoding=UTF8&useSSL=false");
- druidXADataSource.setUsername("root");
- druidXADataSource.setPassword("");
-
- AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
- atomikosDataSourceBean.setXaDataSource(druidXADataSource);
- atomikosDataSourceBean.setUniqueResourceName("teacherDataSource");
- atomikosDataSourceBean.setPoolSize(5);
- return atomikosDataSourceBean;
- }
-
-
- @Bean(name = "teacherSqlSessionFactory")
- public SqlSessionFactory masterSqlSessionFactory(@Qualifier("teacherDataSource") DataSource masterDataSource)
- throws Exception {
- final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
- sessionFactory.setDataSource(masterDataSource);
- return sessionFactory.getObject();
- }
-
- }
这里就不用配置JtaTransactionManager了。
测试:
- @Autowired
- MoviesMapper moviesMapper;
-
- @Autowired
- TeacherMapper teacherMapper;
-
-
- @RequestMapping(method = RequestMethod.GET)
- public MyResponseJson twodata() {
- for (int i = 0;i < 5;i++) {
- if(i < 2) {
- Teacher teacher = new Teacher("3", 10);
- teacherMapper.insertteacher(teacher);
- Movies movies = new Movies("3", "3", 50, 10);
- moviesMapper.insertmovies(movies);
-
- }else {
- throw new RuntimeException();
- }
- }
- return new MyResponseJson(200, "成功!", null);
- }
测试结果:可以回滚