依赖
<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"})
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"})
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 {
@Bean(name
= "primaryDataSource",initMethod
= "init", destroyMethod
= "close")
@Qualifier("primaryDataSource")
@Primary
public DataSource
primaryDataSource(PGProperties pgProperties
) {
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();
}
@Bean
public JpaVendorAdapter
jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter
= new HibernateJpaVendorAdapter();
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注解,这里回滚会出错,提示没有事务。
@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个不同数据源的事务都会回滚。