Springboot + Atomikos + Druid + Mysql 实现JTA分布式事务
DataSource 配置
1 package com.cheng.dynamic.config; 2 3 import java.util.Properties; 4 5 import javax.sql.DataSource; 6 7 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean; 9 import org.springframework.context.annotation.Bean; 10 import org.springframework.context.annotation.Configuration; 11 import org.springframework.context.annotation.Primary; 12 import org.springframework.core.env.Environment; 13 14 @Configuration 15 public class DataSourceConfig { 16 @Autowired 17 private Environment env; 18 19 @Bean(name = "primaryDS") 20 @Primary 21 public DataSource primaryDataSource() throws Exception{ 22 AtomikosDataSourceBean ds = new AtomikosDataSourceBean(); 23 ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource"); 24 ds.setUniqueResourceName("primaryRN"); 25 ds.setPoolSize(5); 26 ds.setXaProperties(build("cheng.primary.datasource.")); 27 return ds; 28 } 29 30 @Bean(name = "secondaryDS") 31 public DataSource dataSource() throws Exception{ 32 AtomikosDataSourceBean ds = new AtomikosDataSourceBean(); 33 ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource"); 34 ds.setUniqueResourceName("secondaryRN"); 35 ds.setPoolSize(5); 36 ds.setXaProperties(build("cheng.secondary.datasource.")); 37 return ds; 38 } 39 40 private Properties build(String prefix) { 41 Properties prop = new Properties(); 42 prop.put("url", env.getProperty(prefix + "url")); 43 prop.put("username", env.getProperty(prefix + "username")); 44 prop.put("password", env.getProperty(prefix + "password")); 45 prop.put("driverClassName", env.getProperty(prefix + "driverClassName")); 46 47 return prop; 48 } 49 }
JtaTransactionManagerConfig
1 package com.cheng.dynamic.config; 2 3 import javax.transaction.UserTransaction; 4 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 import org.springframework.transaction.jta.JtaTransactionManager; 8 9 import com.atomikos.icatch.jta.UserTransactionImp; 10 import com.atomikos.icatch.jta.UserTransactionManager; 11 12 @Configuration 13 public class JtaTransactionManagerConfig { 14 @Bean(name = "xatx") 15 public JtaTransactionManager regTransactionManager () { 16 UserTransactionManager userTransactionManager = new UserTransactionManager(); 17 UserTransaction userTransaction = new UserTransactionImp(); 18 return new JtaTransactionManager(userTransaction, userTransactionManager); 19 } 20 }
RepositoryPrimaryConfig
1 package com.cheng.dynamic.config; 2 3 import javax.sql.DataSource; 4 5 import org.apache.ibatis.session.SqlSessionFactory; 6 import org.mybatis.spring.SqlSessionFactoryBean; 7 import org.mybatis.spring.SqlSessionTemplate; 8 import org.mybatis.spring.annotation.MapperScan; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.beans.factory.annotation.Qualifier; 11 import org.springframework.context.annotation.Bean; 12 import org.springframework.context.annotation.Configuration; 13 import org.springframework.context.annotation.Primary; 14 import org.springframework.core.env.Environment; 15 import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 16 17 @Configuration 18 @MapperScan(basePackages = "com.cheng.dynamic.repository.primary", sqlSessionTemplateRef = "sqlSessionTemplatePrimary") 19 public class RepositoryPrimaryConfig { 20 @Autowired 21 private Environment env; 22 @Autowired 23 @Qualifier("primaryDS") 24 private DataSource primaryDS; 25 26 @Bean(name="sqlSessionFactoryPrimary") 27 @Primary 28 public SqlSessionFactory sqlSessionFactoryPrimary() throws Exception{ 29 SqlSessionFactoryBean fb = new SqlSessionFactoryBean(); 30 fb.setDataSource(primaryDS); 31 fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));//指定基包 32 fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapperLocations")));//指定xml文件位置 33 return fb.getObject(); 34 } 35 36 @Bean(name = "sqlSessionTemplatePrimary") 37 @Primary 38 public SqlSessionTemplate sqlSessionTemplatePrimary(@Qualifier("sqlSessionFactoryPrimary") SqlSessionFactory sqlSessionFactory) throws Exception { 39 SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory); 40 return sqlSessionTemplate; 41 } 42 }
RepositorySecondaryConfig
1 package com.cheng.dynamic.config; 2 3 import javax.sql.DataSource; 4 5 import org.apache.ibatis.session.SqlSessionFactory; 6 import org.mybatis.spring.SqlSessionFactoryBean; 7 import org.mybatis.spring.SqlSessionTemplate; 8 import org.mybatis.spring.annotation.MapperScan; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.beans.factory.annotation.Qualifier; 11 import org.springframework.context.annotation.Bean; 12 import org.springframework.context.annotation.Configuration; 13 import org.springframework.core.env.Environment; 14 import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 15 16 @Configuration 17 @MapperScan(basePackages = "com.cheng.dynamic.repository.secondary", sqlSessionTemplateRef = "sqlSessionTemplateSecondary") 18 public class RepositorySecondaryConfig { 19 @Autowired 20 private Environment env; 21 @Autowired 22 @Qualifier("secondaryDS") 23 private DataSource secondaryDS; 24 25 @Bean(name="sqlSessionFactorySecondary") 26 public SqlSessionFactory sqlSessionFactorySecondary() throws Exception{ 27 SqlSessionFactoryBean fb = new SqlSessionFactoryBean(); 28 fb.setDataSource(secondaryDS); 29 fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage2"));//指定基包 30 fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapperLocations2")));//指定xml文件位置 31 return fb.getObject(); 32 } 33 34 @Bean(name = "sqlSessionTemplateSecondary") 35 public SqlSessionTemplate sqlSessionTemplateSecondary(@Qualifier("sqlSessionFactorySecondary") SqlSessionFactory sqlSessionFactory) throws Exception { 36 return new SqlSessionTemplate(sqlSessionFactory); 37 } 38 }
Test1Service
1 package com.cheng.dynamic.service; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 import org.springframework.transaction.annotation.Transactional; 6 7 import com.cheng.dynamic.entity.Test1; 8 import com.cheng.dynamic.entity.Test2; 9 import com.cheng.dynamic.repository.primary.Test1Dao; 10 11 @Service 12 @Transactional 13 public class Test1Service { 14 @Autowired 15 private Test1Dao test1Dao; 16 @Autowired 17 private Test2Service test2Service; 18 19 public void test(){ 20 System.out.println(test1Dao); 21 } 22 23 public void add(Test1 t){ 24 System.out.println(test1Dao.add(t)); 25 System.out.println(t.getId()); 26 } 27 28 public void save(){ 29 Test1 t1 = new Test1(); 30 t1.setName("t1"); 31 add(t1); 32 // System.out.println(1/0); 33 Test2 t2 = new Test2(); 34 t2.setName("t2"); 35 test2Service.add(t2); 36 } 37 }
测试类
1 package com.cheng.dynamic.service; 2 3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.boot.test.context.SpringBootTest; 7 import org.springframework.test.annotation.Rollback; 8 import org.springframework.test.context.junit4.SpringRunner; 9 import org.springframework.transaction.annotation.Transactional; 10 11 @RunWith(SpringRunner.class) 12 @SpringBootTest() 13 @Transactional(transactionManager = "xatx") 14 @Rollback(false) 15 public class Test1ServiceTest { 16 @Autowired 17 private Test1Service test1Service; 18 @Test 19 public void testTest() throws Exception { 20 test1Service.save(); 21 } 22 23 }
druid监控配置
1 package com.cheng.dynamic.config; 2 3 import org.springframework.boot.web.servlet.FilterRegistrationBean; 4 import org.springframework.boot.web.servlet.ServletRegistrationBean; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 8 import com.alibaba.druid.filter.stat.StatFilter; 9 import com.alibaba.druid.support.http.StatViewServlet; 10 import com.alibaba.druid.support.http.WebStatFilter; 11 import com.alibaba.druid.wall.WallConfig; 12 import com.alibaba.druid.wall.WallFilter; 13 14 @Configuration 15 public class DruidConfig { 16 @Bean 17 public ServletRegistrationBean<StatViewServlet> druidServlet() { 18 ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*"); 19 20 //控制台管理用户,加入下面2行 进入druid后台就需要登录 21 //servletRegistrationBean.addInitParameter("loginUsername", "admin"); 22 //servletRegistrationBean.addInitParameter("loginPassword", "admin"); 23 return servletRegistrationBean; 24 } 25 26 @Bean 27 public FilterRegistrationBean<WebStatFilter> filterRegistrationBean() { 28 FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>(); 29 filterRegistrationBean.setFilter(new WebStatFilter()); 30 filterRegistrationBean.addUrlPatterns("/*"); 31 filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); 32 filterRegistrationBean.addInitParameter("profileEnable", "true"); 33 return filterRegistrationBean; 34 } 35 36 @Bean 37 public StatFilter statFilter(){ 38 StatFilter statFilter = new StatFilter(); 39 statFilter.setLogSlowSql(true); //slowSqlMillis用来配置SQL慢的标准,执行时间超过slowSqlMillis的就是慢。 40 statFilter.setMergeSql(true); //SQL合并配置 41 statFilter.setSlowSqlMillis(1000);//slowSqlMillis的缺省值为3000,也就是3秒。 42 return statFilter; 43 } 44 45 @Bean 46 public WallFilter wallFilter(){ 47 WallFilter wallFilter = new WallFilter(); 48 //允许执行多条SQL 49 WallConfig config = new WallConfig(); 50 config.setMultiStatementAllow(true); 51 wallFilter.setConfig(config); 52 return wallFilter; 53 } 54 }
完整代码:https://github.com/lucheng/jta.git
其它:
SpringBoot 多数据源配置 https://github.com/lucheng/dynamic.git
SpringBoot 多数据源 + 动态数据源配置:https://github.com/lucheng/dynamicDatasource.git