依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
配置
# 多数据源配置
spring:
datasource:
ds1:
driverClassName: org.postgresql.Driver
jdbcUrl: jdbc:postgresql://xxx/bigdata?currentSchema=public
username: xxx
password: xxx
ds3:
driverClassName: org.postgresql.Driver
jdbcUrl: jdbc:postgresql://xxx/xxx?currentSchema=public
username: xxxx
password: xxxx
jpa:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
open-in-view: true
show-sql: true
database-platform: org.hibernate.dialect.PostgreSQLDialect
配置类
@Configuration
@ConfigurationProperties(prefix = "spring.datasource.ds2")
@Data
public class GPProperties {
private String jdbcUrl;
private String username;
private String password;
private String driverClassName;
}
@Configuration
@ConfigurationProperties(prefix = "spring.datasource.ds1")
@Data
public class PGProperties {
private String jdbcUrl;
private String username;
private String password;
private String driverClassName;
}
@Configuration
@EnableTransactionManagement
@DependsOn("transactionManager")
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerPrimary",
transactionManagerRef = "transactionManager",
basePackages = {
"com.kanq.bigdata.greenplum.dao.ds1"}) //设置Repository所在位置
public class PrimaryConfig {
@Autowired
private JpaVendorAdapter jpaVendorAdapter;
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;
@Bean(name = "entityManagerPrimary")
public LocalContainerEntityManagerFactoryBean orderEntityManager() throws Throwable {
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
properties.put("javax.persistence.transactionType", "JTA");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJtaDataSource(primaryDataSource);
entityManager.setJpaVendorAdapter(jpaVendorAdapter);
entityManager.setPackagesToScan("com.kanq.bigdata.greenplum.entity.pg");
entityManager.setPersistenceUnitName("layerPersistenceUnit");
entityManager.setJpaPropertyMap(properties);
return entityManager;
}
}
@Configuration
@DependsOn("transactionManager")
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerSecond",
transactionManagerRef = "transactionManager",
basePackages = {
"com.kanq.bigdata.greenplum.dao.ds2"}) //设置Repository所在位置
public class SecondConfig {
@Autowired
private JpaVendorAdapter jpaVendorAdapter;
@Autowired
@Qualifier("secondDataSource")
private DataSource secondDataSource;
@Bean(name = "entityManagerSecond")
public LocalContainerEntityManagerFactoryBean orderEntityManager() throws Throwable {
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
properties.put("javax.persistence.transactionType", "JTA");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJtaDataSource(secondDataSource);
entityManager.setJpaVendorAdapter(jpaVendorAdapter);
entityManager.setPackagesToScan("com.kanq.bigdata.greenplum.entity.gp");
entityManager.setPersistenceUnitName("metaPersistenceUnit");
entityManager.setJpaPropertyMap(properties);
return entityManager;
}
}
@Configuration
@ComponentScan
@EnableTransactionManagement
public class DataSourceConfig {
// @ConfigurationProperties(prefix="spring.datasource.ds1")
@Bean(name = "primaryDataSource",initMethod = "init", destroyMethod = "close")
@Qualifier("primaryDataSource")
@Primary
public DataSource primaryDataSource(PGProperties pgProperties) {
// DataSource pg = DataSourceBuilder.create().build();
PGXADataSource pgxa=new PGXADataSource();
pgxa.setURL(pgProperties.getJdbcUrl());
pgxa.setUser(pgProperties.getUsername());
pgxa.setPassword(pgProperties.getPassword());
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(pgxa);
xaDataSource.setUniqueResourceName("primaryDataSource");
return xaDataSource;
}
@Bean(name = "secondDataSource")
@Qualifier("secondDataSource")
public DataSource secondaryDataSource(GPProperties gpProperties) {
PGXADataSource gpxa=new PGXADataSource();
gpxa.setURL(gpProperties.getJdbcUrl());
gpxa.setUser(gpProperties.getUsername());
gpxa.setPassword(gpProperties.getPassword());
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(gpxa);
xaDataSource.setUniqueResourceName("secondDataSource");
return xaDataSource;
}
@Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
//设置JPA特性
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
//显示sql
hibernateJpaVendorAdapter.setShowSql(true);
//自动生成/更新表
hibernateJpaVendorAdapter.setGenerateDdl(false);
//设置数据库类型
hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);
return hibernateJpaVendorAdapter;
}
@Bean(name = "atomikosTransactionManager",initMethod = "init", destroyMethod = "close")
public TransactionManager atomikosTransactionManager() throws Throwable {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
AtomikosJtaPlatform.transactionManager = userTransactionManager;
return userTransactionManager;
}
@Bean(name = "userTransaction")
public UserTransaction userTransaction() throws Throwable {
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(10000);
return userTransactionImp;
}
@Bean(name = "transactionManager")
@DependsOn({
"userTransaction", "atomikosTransactionManager"})
public PlatformTransactionManager transactionManager() throws Throwable {
UserTransaction userTransaction = userTransaction();
AtomikosJtaPlatform.transaction = userTransaction;
TransactionManager atomikosTransactionManager = atomikosTransactionManager();
return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
}
}
import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
public class AtomikosJtaPlatform extends AbstractJtaPlatform {
private static final long serialVersionUID = 1L;
static TransactionManager transactionManager;
static UserTransaction transaction;
@Override
protected TransactionManager locateTransactionManager() {
return transactionManager;
}
@Override
protected UserTransaction locateUserTransaction() {
return transaction;
}
}
Entity、Repository
Entity、Repository都需要分2个文件夹,配置中配置了不同数据源使用不同的文件夹
略
Controller
需要加事务@Transactional
@RequestMapping(value = "/test", method = RequestMethod.POST)
@Transactional
public ResultModel test(){
Map<String,Object> res=null;
res=service.test();
return Message.success(res);
}
Service
如果Controller没有@Transactional注解,这里回滚会出错,提示没有事务。
//atomikos事务
@Transactional
public boolean test(){
try {
XXX xxx=new XXX("wo",1);
YYY yyy=new YYY("qaq",2);
xxxDao.saveAndFlush(xxx);
yyyDao.saveAndFlush(yyy);
}catch (Exception e){
log.error("数据更新异常",e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return false;
}
return true;
}
2个不同数据源的事务都会回滚。