springboot-JTA
文章目录
springboot无配置多数据源分布式数据事务管理
使用atomikos解决多数据源分布式事务问题
atomikos官网是这样描述atomikos的使用的:
It is easy to setup by using its setter methods but can also be easily built from a Spring BeanFactory. Here is an example of code that creates an AtomikosDataSourceBean with 5 connections in pool on an Oracle database:
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
ds.setUniqueResourceName(“oracle”);
ds.setXaDataSourceClassName(“oracle.jdbc.xa.client.OracleXADataSource”);
Properties p = new Properties();
p.setProperty ( “user” , “java” );
p.setProperty ( “password” , “java” );
p.setProperty ( “URL” , “jdbc:oracle:thin:@localhost-xe:1521:XE” );
ds.setXaDataSourceProperties ( p );
ds.setPoolSize ( 5 );
可以这样设置生成database,并初始化sql:
`EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.H2) //等价于设置url=jdbc:h2:mem:testdb
.addScript("primarySchema.sql")
.build();
return db;
`
项目pom.xml:
`\<?xml version="1.0" encoding="UTF-8"?\>
\<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"\>
\<modelVersion\>4.0.0\</modelVersion\>
\<groupId\>com.example\</groupId\>
\<artifactId\>demo1\</artifactId\>
\<version\>0.0.1-SNAPSHOT\</version\>
\<packaging\>jar\</packaging\>
\<name\>demo1\</name\>
\<description\>Demo project for Spring Boot\</description\>
\<parent\>
\<groupId\>org.springframework.boot\</groupId\>
\<artifactId\>spring-boot-starter-parent\</artifactId\>
\<version\>1.5.6.RELEASE\</version\>
\<relativePath/\> \<!-- lookup parent from repository --\>
\</parent\>
\<properties\>
\<project.build.sourceEncoding\>UTF-8\</project.build.sourceEncoding\>
\<project.reporting.outputEncoding\>UTF-8\</project.reporting.outputEncoding\>
\<java.version\>1.8\</java.version\>
\</properties\>
\<dependencies\>
\<dependency\>
\<groupId\>org.springframework.boot\</groupId\>
\<artifactId\>spring-boot-starter-aop\</artifactId\>
\</dependency\>
\<dependency\>
\<groupId\>org.springframework.boot\</groupId\>
\<artifactId\>spring-boot-starter-web\</artifactId\>
\</dependency\>
\<dependency\>
\<groupId\>org.mybatis.spring.boot\</groupId\>
\<artifactId\>mybatis-spring-boot-starter\</artifactId\>
\<version\>1.3.0\</version\>
\</dependency\>
\<dependency\>
\<groupId\>org.springframework.boot\</groupId\>
\<artifactId\>spring-boot-starter-jta-atomikos\</artifactId\>
\</dependency\>
\<dependency\>
\<groupId\>com.h2database\</groupId\>
\<artifactId\>h2\</artifactId\>
\<scope\>runtime\</scope\>
\</dependency\>
\<dependency\>
\<groupId\>org.projectlombok\</groupId\>
\<artifactId\>lombok\</artifactId\>
\<optional\>true\</optional\>
\</dependency\>
\<dependency\>
\<groupId\>org.springframework.boot\</groupId\>
\<artifactId\>spring-boot-starter-test\</artifactId\>
\<scope\>test\</scope\>
\</dependency\>
\</dependencies\>
\<build\>
\<plugins\>
\<plugin\>
\<groupId\>org.springframework.boot\</groupId\>
\<artifactId\>spring-boot-maven-plugin\</artifactId\>
\</plugin\>
\</plugins\>
\</build\>
\<repositories\>
\<repository\>
\<id\>alimaven\</id\>
\<url\>http://maven.aliyun.com/nexus/content/groups/public/\</url\>
\</repository\>
\<repository\>
\<id\>spring-snapshots\</id\>
\<url\>http://repo.spring.io/snapshot\</url\>
\<snapshots\>\<enabled\>true\</enabled\>\</snapshots\>
\</repository\>
\<repository\>
\<id\>spring-milestones\</id\>
\<url\>http://repo.spring.io/milestone\</url\>
\</repository\>
\</repositories\>
\</project\>
`
主数据源配置
`package com.example.demo;
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.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import javax.sql.DataSource;
import java.util.Properties;
/** * Created by sam on 2017/7/30.
*/
@Configuration
@MapperScan(value = "com.example.demo.mapper.primary",sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDataSourceConfig {
@Bean(name = "primaryDataSource")
@Primary
public DataSource primaryDataSource(){
System.out.println("-------primary dataSource-------init");
AtomikosDataSourceBean dataSourceBean = new AtomikosDataSourceBean();
dataSourceBean.setXaDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
Properties pts = new Properties();
pts.setProperty("url","jdbc:h2:mem:PMDB;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
pts.setProperty("user","sa");
pts.setProperty("password","");
dataSourceBean.setXaProperties(pts);
dataSourceBean.setPoolSize(1);
dataSourceBean.setMaxPoolSize(3);
return dataSourceBean;
}
//第一种方式
// @Bean(name = "primaryDataSource")
// @Primary
// @ConfigurationProperties(prefix = "primary.datasource")
// public DataSource primaryDataSource(){
// System.out.println("-------primary dataSource-------init");
// return DataSourceBuilder.create().build();
// }
//第二种方式
// @Bean(name = "primaryDataSource")
// @Primary
// public DataSource primaryDataSource(){
// System.out.println("-------primary dataSource-------init");
// EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
// EmbeddedDatabase db = builder
// .setType(EmbeddedDatabaseType.H2) //等价于设置url=jdbc:h2:mem:testdb
// .addScript("primarySchema.sql")
// .build();
// return db;
// }
@Bean
public DataSourceInitializer primaryInitSql(@Qualifier("primaryDataSource") DataSource dataSource){
return init(dataSource,"primarySchema");
}
private DataSourceInitializer init(DataSource dataSource,String schameName){
DataSourceInitializer dsi = new DataSourceInitializer();
dsi.setDataSource(dataSource);
dsi.setDatabasePopulator(new ResourceDatabasePopulator(new ClassPathResource(schameName+".sql")));
return dsi;
}
@Bean(name = "primarySqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
}
`
副数据源配置
`package com.example.demo;
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.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import javax.sql.DataSource;
import java.util.Properties;
/** * Created by sam on 2017/7/30.
*/
@Configuration
@MapperScan(value = "com.example.demo.mapper.second",sqlSessionFactoryRef = "secondSqlSessionFactory")
public class SecondDataSourceConfig {
@Bean(name = "secondDataSource")
public DataSource secondDataSource(){
System.out.println("-------second dataSource-------init");
AtomikosDataSourceBean dataSourceBean = new AtomikosDataSourceBean();
dataSourceBean.setXaDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
Properties pts = new Properties();
pts.setProperty("url","jdbc:h2:mem:SCDB;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
pts.setProperty("user","sa");
pts.setProperty("password","");
dataSourceBean.setXaProperties(pts);
dataSourceBean.setPoolSize(1);
dataSourceBean.setMaxPoolSize(3);
return dataSourceBean;
}
@Bean
public DataSourceInitializer secondInitSql(@Qualifier("secondDataSource") DataSource dataSource){
return init(dataSource,"secondSchema");
}
private DataSourceInitializer init(DataSource dataSource,String schameName){
DataSourceInitializer dsi = new DataSourceInitializer();
dsi.setDataSource(dataSource);
dsi.setDatabasePopulator(new ResourceDatabasePopulator(new ClassPathResource(schameName+".sql")));
return dsi;
}
@Bean(name = "secondSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
}
`
atomikos分布式事务配置
`package com.example.demo;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.transaction.SystemException;
/** * Created by sam on 2017/8/2.
*/
@Configuration
public class AtomikosTXAConfig implements TransactionManagementConfigurer {
@Bean(name = "atomikosTransactionManager")
public UserTransactionManager atomikosTransactionManager(){
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(true);
return userTransactionManager;
}
@Bean(name = "atomikosUserTransaction")
public UserTransactionImp atomikosUserTransaction(){
UserTransactionImp atomikosUserTransation =new UserTransactionImp();
try {
atomikosUserTransation.setTransactionTimeout(100);
} catch (SystemException e) {
e.printStackTrace();
}
return atomikosUserTransation;
}
@Bean
public JtaTransactionManager txManager() {
return new JtaTransactionManager(atomikosUserTransaction(),atomikosTransactionManager());
}
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return txManager();
}
}
`