链式事务管理器
配置的实例将按给定的顺序启动事务,并按相反的顺序提交/回滚,这意味着最有可能破坏事务的 PlatformTransactionManager 应该是配置列表中的最后一个。
如果您按以下顺序链接交易:交易1,交易2
transaction1 begin
transaction2 begin
transaction2 commit -> error rollbacks, rollbacks transction1 too
transaction1 commit -> error, only rollbacks transaction1
案子insert -> DB1 -> SUCCESSFUL insert -> DB2 -> ERROR ROLLBACK DB1
工作中。
But, 如果你有insert -> DB1 -> FAIL ROLLBAK DB1 -> DB2 -> SUCCESSFUL
,插入是为 DB2 而不是 DB1 提交的。更多详情请参阅本文 https://dzone.com/articles/most-common-spring-transactional-mistakes.
如果您对此感到满意,您可以在项目中复制该类并继续使用它:https://github.com/spring-projects/spring-data-commons/issues/2232#issuecomment-1018473289 https://github.com/spring-projects/spring-data-commons/issues/2232#issuecomment-1018473289
JtaTransactionManager 与 Atomikos
为了让所有事务在失败时回滚,我更改了我的conf以使用JtaTransactionManager(带有spring boot和posgtres)。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
应用程序属性
my.datasource.one.unique-resource-name=
my.datasource.one.xa-properties.url=jdbc:postgresql://
my.datasource.one.xa-data-source-class-name=org.postgresql.xa.PGXADataSource
my.datasource.one.xa-properties.user=
my.datasource.one.xa-properties.password=
my.datasource.one.max-pool-size=
my.datasource.one.min-pool-size=
my.datasource.two.unique-resource-name=
my.datasource.two.xa-properties.url=jdbc:postgresql://
my.datasource.two.xa-data-source-class-name=org.postgresql.xa.PGXADataSource
my.datasource.two.xa-properties.user=
my.datasource.two.xa-properties.password=
my.datasource.two.max-pool-size=
my.datasource.two.min-pool-size=
@Bean
@Primary
@ConfigurationProperties("my.datasource.one")
public DataSource dataSourceOne() {
return new AtomikosDataSourceBean();
}
@Bean("entityManagerOne")
@DependsOn("transactionManager")
public LocalContainerEntityManagerFactoryBean entityManagerOne(@Autowired JpaVendorAdapter jpaVendorAdapter) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.default_schema", "public");
properties.put("hibernate.ddl-auto", "none");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJtaDataSource(dataSourceOne());
entityManager.setJpaVendorAdapter(jpaVendorAdapter);
entityManager.setPackagesToScan("");
entityManager.setPersistenceUnitName("");
entityManager.setJpaPropertyMap(properties);
return entityManager;
}
@Bean
@Primary
@ConfigurationProperties("my.datasource.two")
public DataSource dataSourceTwo() {
return new AtomikosDataSourceBean();
}
@Bean("entityManagerTwo")
@DependsOn("transactionManager")
public LocalContainerEntityManagerFactoryBean entityManagerTwo(@Autowired JpaVendorAdapter jpaVendorAdapter) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.default_schema", "public");
properties.put("hibernate.ddl-auto", "none");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJtaDataSource(dataSourceTwo());
entityManager.setJpaVendorAdapter(jpaVendorAdapter);
entityManager.setPackagesToScan("");
entityManager.setPersistenceUnitName("");
entityManager.setJpaPropertyMap(properties);
return entityManager;
}
jta.属性
com.atomikos.icatch.enable_logging=false
com.atomikos.icatch.default_jta_timeout=60000000
com.atomikos.icatch.max_timeout=100000000
com.atomikos.icatch.threaded_2pc=true
@Bean
public JpaVendorAdapter jpaVendorAdapter(@Autowired Environment env) {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
return hibernateJpaVendorAdapter;
}
@Bean
public UserTransaction userTransaction() throws SystemException {
var userTransaction = new UserTransactionImp();
userTransaction.setTransactionTimeout(60000);
return userTransaction;
}
@Bean
public TransactionManager atomikosTransactionManager() throws SystemException {
var userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(true);
return userTransactionManager;
}
@Bean
public PlatformTransactionManager transactionManager(@Autowired UserTransaction userTransaction, @Autowired TransactionManager atomikosTransactionManager) throws Throwable {
return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
}
为 postgres 启用准备好的事务
postgresql.conf
max_prepared_transactions = 100 # zero disables the feature
帮助我得到这个的来源:
https://www.baeldung.com/java-atomikos https://www.baeldung.com/java-atomikos
http://www.thedevpiece.com/configuring-multiple-datasources-using-springboot-and-atomikos/ http://www.thedevpiece.com/configuring-multiple-datasources-using-springboot-and-atomikos/
https://github.com/YihuaWanglv/spring-boot-jta-atomikos-sample https://github.com/YihuaWanglv/spring-boot-jta-atomikos-sample