(十二)Spring Boot+Druid+Mybatis实现JTA分布式事务

来源:互联网 发布:梯形螺纹加工编程 编辑:程序博客网 时间:2024/04/27 12:50
源码下载:点此下载  整合Mybatis 配置两个SqlSessionFactory 分别扫描不同的包
对于分布式事务而言, JTA 是一个不错的解决方案,通常 JTA 需要应用服务器的支持,但在查阅 SpringBoot 的文档时发现,它推荐了 Atomikos 和 Bitronix 两种无需服务器支持的分布式事务组件,在这两个组件中, Atomikos 更受大家的好评,所以我选择使用它.

引入依赖

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

application.properties

#配置jdbc数据源#配置多数据源#数据源名称(与下列配置的数据源对应,多个数据源要配多个名称)jdbc.datasources=ds,ds1jdbc.ds.driverClassName=com.mysql.jdbc.Driverjdbc.ds.url=jdbc\:mysql\://localhost\:3306/ryx?characterEncoding\=UTF-8&pinGlobalTxToPhysicalConnection\=truejdbc.ds.username=rootjdbc.ds.password=123456jdbc.ds1.driverClassName=com.mysql.jdbc.Driverjdbc.ds1.url=jdbc\:mysql\://172.20.1.5\:3306/ryx?characterEncoding\=UTF-8&pinGlobalTxToPhysicalConnection\=truejdbc.ds1.username=rootjdbc.ds1.password=root#druid监控平台账号密码druid.username=rootdruid.password=Ruyixing2017
注意:使用Druid配置JTA事务需要使用DruidXADataSource,不要再使用DruidDataSource了

TestMyBatisConfig.java

package com.test.springboot.config.datasource;import java.sql.SQLException;import javax.sql.DataSource;import org.apache.ibatis.session.SqlSessionFactory;import org.mybatis.spring.SqlSessionFactoryBean;import org.mybatis.spring.SqlSessionTemplate;import org.mybatis.spring.annotation.MapperScan;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import com.alibaba.druid.pool.DruidDataSource;import com.alibaba.druid.pool.xa.DruidXADataSource;import com.atomikos.jdbc.AtomikosDataSourceBean;import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;@Configuration// basePackages 最好分开配置 如果放在同一个文件夹可能会报错@MapperScan(basePackages = "com.test.springboot.dao", sqlSessionTemplateRef = "testSqlSessionTemplate")public class TestMyBatisConfig {@Value("${jdbc.ds.driverClassName}")private String driver;@Value("${jdbc.ds.url}")private String url;@Value("${jdbc.ds.username}")private String username;@Value("${jdbc.ds.password}")private String password;// 配置数据源@Primary@Bean(name = "testDataSource",initMethod="init",destroyMethod="close")public DataSource dataSource() throws SQLException{DruidXADataSource dataSource=new DruidXADataSource();//DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);        dataSource.setPassword(password);        //配置最大连接        dataSource.setMaxActive(300);        //配置初始连接        dataSource.setInitialSize(20);        //配置最小连接        dataSource.setMinIdle(10);        //连接等待超时时间        dataSource.setMaxWait(60000);        //间隔多久进行检测,关闭空闲连接        dataSource.setTimeBetweenEvictionRunsMillis(60000);        //一个连接最小生存时间        dataSource.setMinEvictableIdleTimeMillis(300000);        //连接等待超时时间 单位为毫秒 缺省启用公平锁,        //并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁        dataSource.setUseUnfairLock(true);        //用来检测是否有效的sql        dataSource.setValidationQuery("select 'x'");        dataSource.setTestWhileIdle(true);        //申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能        dataSource.setTestOnBorrow(false);        //归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能        dataSource.setTestOnReturn(false);        //打开PSCache,并指定每个连接的PSCache大小启用poolPreparedStatements后,        //PreparedStatements 和CallableStatements 都会被缓存起来复用,        //即相同逻辑的SQL可以复用一个游标,这样可以减少创建游标的数量。        dataSource.setPoolPreparedStatements(true);        dataSource.setMaxOpenPreparedStatements(20);        //配置sql监控的filter        dataSource.setFilters("stat,wall,log4j");        try {            dataSource.init();        } catch (SQLException e) {            e.printStackTrace();        }        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();        xaDataSource.setXaDataSource(dataSource);xaDataSource.setUniqueResourceName("testDataSource");/*xaDataSource.setMinPoolSize(10);xaDataSource.setMaxPoolSize(300);xaDataSource.setMaxLifetime(20000);xaDataSource.setBorrowConnectionTimeout(30);xaDataSource.setLoginTimeout(30);xaDataSource.setMaintenanceInterval(60);xaDataSource.setMaxIdleTime(60);xaDataSource.setTestQuery("select 'x'");*/        return xaDataSource;}@Bean(name = "testSqlSessionFactory")public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource)throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);//bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/test/springboot/dao/*.xml"));return bean.getObject();}@Bean(name = "testSqlSessionTemplate")public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}}

Test2MyBatisConfig.java

package com.test.springboot.config.datasource;import java.sql.SQLException;import javax.sql.DataSource;import org.apache.ibatis.session.SqlSessionFactory;import org.mybatis.spring.SqlSessionFactoryBean;import org.mybatis.spring.SqlSessionTemplate;import org.mybatis.spring.annotation.MapperScan;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import com.alibaba.druid.pool.DruidDataSource;import com.alibaba.druid.pool.xa.DruidXADataSource;import com.atomikos.jdbc.AtomikosDataSourceBean;import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;@Configuration@MapperScan(basePackages = "com.test.springboot.dao2", sqlSessionTemplateRef = "test2SqlSessionTemplate")public class Test2MyBatisConfig {@Value("${jdbc.ds1.driverClassName}")private String driver;@Value("${jdbc.ds1.url}")private String url;@Value("${jdbc.ds1.username}")private String username;@Value("${jdbc.ds1.password}")private String password;@Bean(name = "test2DataSource",initMethod="init",destroyMethod="close")public DataSource dataSource() throws SQLException{DruidXADataSource dataSource=new DruidXADataSource();//DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);        dataSource.setPassword(password);        //配置最大连接        dataSource.setMaxActive(300);        //配置初始连接        dataSource.setInitialSize(20);        //配置最小连接        dataSource.setMinIdle(10);        //连接等待超时时间        dataSource.setMaxWait(60000);        //间隔多久进行检测,关闭空闲连接        dataSource.setTimeBetweenEvictionRunsMillis(60000);        //一个连接最小生存时间        dataSource.setMinEvictableIdleTimeMillis(300000);        //连接等待超时时间 单位为毫秒 缺省启用公平锁,        //并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁        dataSource.setUseUnfairLock(true);        //用来检测是否有效的sql        dataSource.setValidationQuery("select 'x'");        dataSource.setTestWhileIdle(true);        //申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能        dataSource.setTestOnBorrow(false);        //归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能        dataSource.setTestOnReturn(false);        //打开PSCache,并指定每个连接的PSCache大小启用poolPreparedStatements后,        //PreparedStatements 和CallableStatements 都会被缓存起来复用,        //即相同逻辑的SQL可以复用一个游标,这样可以减少创建游标的数量。        dataSource.setPoolPreparedStatements(true);        dataSource.setMaxOpenPreparedStatements(20);        //配置sql监控的filter        dataSource.setFilters("stat,wall,log4j");        try {            dataSource.init();        } catch (SQLException e) {           e.printStackTrace();        }        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();        xaDataSource.setXaDataSource(dataSource);xaDataSource.setUniqueResourceName("test2DataSource");/*xaDataSource.setMinPoolSize(10);xaDataSource.setMaxPoolSize(300);xaDataSource.setMaxLifetime(20000);xaDataSource.setBorrowConnectionTimeout(30);xaDataSource.setLoginTimeout(30);xaDataSource.setMaintenanceInterval(60);xaDataSource.setMaxIdleTime(60);xaDataSource.setTestQuery("select 'x'");*/        return xaDataSource;}@Bean(name = "test2SqlSessionFactory")public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);//bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/test/springboot/dao2/*.xml"));return bean.getObject();}@Bean(name = "test2SqlSessionTemplate")public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}}

然后要配置JTA事务管理

TransactionManagerConfig.java

package com.test.springboot.config.datasource;import javax.transaction.TransactionManager;import javax.transaction.UserTransaction;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import org.springframework.transaction.PlatformTransactionManager;import org.springframework.transaction.annotation.EnableTransactionManagement;import org.springframework.transaction.jta.JtaTransactionManager;import com.atomikos.icatch.jta.UserTransactionImp;import com.atomikos.icatch.jta.UserTransactionManager;@Configuration@ComponentScan@EnableTransactionManagementpublic class TransactionManagerConfig {@Bean(name = "userTransaction")public UserTransaction userTransaction() throws Throwable {UserTransactionImp userTransactionImp = new UserTransactionImp();userTransactionImp.setTransactionTimeout(10000);return userTransactionImp;}@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")public TransactionManager atomikosTransactionManager() throws Throwable {UserTransactionManager userTransactionManager = new UserTransactionManager();userTransactionManager.setForceShutdown(false);return userTransactionManager;}@Bean(name = "transactionManager")@DependsOn({ "userTransaction", "atomikosTransactionManager" })public PlatformTransactionManager transactionManager() throws Throwable {UserTransaction userTransaction = userTransaction();JtaTransactionManager manager = new JtaTransactionManager(userTransaction,atomikosTransactionManager());return manager;}}

测试方法

在需要事务的service方法内注入两个数据库的操作对应的mapper,然后在方法上标注@Transactional注解就可以了,跟之前使用方法没什么两样
@Override@Transactionalpublic Integer insetStudent(Student student) {Integer integer = studentMapper.insetStudent(student);Integer integer2 = studentMapper2.insetStudent(student);int a=10/0;return integer;}


阅读全文
1 0
原创粉丝点击