跨两个数据源的事务管理(ChainedTransactionManager)-SpringBoot

ash*_*ain 12 spring spring-transactions spring-data spring-boot

为什么 SpringChainedTransactionManager被弃用了?Spring 是否提供任何替代库来支持多个事务管理器?

我的用例:- 我们正在构建一个连接到两个数据源(db1 和 db2)的 Spring Boot 应用程序,它对两个数据库(db1 和 db2)执行插入操作。我们的要求是这样的:插入 -> DB1 -> 成功插入 -> DB2 -> 错误回滚 DB1

目前,我们正在使用ChaninedTransactionManager并且它按预期工作,但我可以看到 lib 已被弃用。那么,只是想确保使用它是否安全,或者 Spring 是否提供了任何我们可以用来替代它的替代库?

小智 10

链式事务管理器

配置的实例将按给定的顺序启动事务,并按相反的顺序提交/回滚,这意味着最有可能破坏事务的 PlatformTransactionManager 应该是配置列表中的最后一个。

如果您按以下顺序链接交易:交易1,交易2

transaction1 begin
  transaction2 begin
  transaction2 commit -> error rollbacks, rollbacks transction1 too
transaction1 commit -> error, only rollbacks transaction1
Run Code Online (Sandbox Code Playgroud)

案件insert -> DB1 -> SUCCESSFUL insert -> DB2 -> ERROR ROLLBACK DB1正在审理中。

但是,如果您有的话insert -> DB1 -> FAIL ROLLBAK DB1 -> DB2 -> SUCCESSFUL,插入是为 DB2 提交的,而不是为 DB1 提交的。更多详细信息请参阅本文

如果您对此感到满意,您可以在项目中复制该类并继续使用它: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>
Run Code Online (Sandbox Code Playgroud)

应用程序属性

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=
Run Code Online (Sandbox Code Playgroud)
    @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;
    }
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)
    @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);
    }
Run Code Online (Sandbox Code Playgroud)

为 postgres 启用准备好的事务

postgresql.conf

max_prepared_transactions = 100     # zero disables the feature
Run Code Online (Sandbox Code Playgroud)

帮助我得到这个的来源:

https://www.baeldung.com/java-atomikos

http://www.thedevpiece.com/configuring-multiple-datasources-using-springboot-and-atomikos/

https://github.com/YihuaWanglv/spring-boot-jta-atomikos-sample


Ant*_*sss 1

因为API有改进。来自文档 https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/transaction/ChainedTransactionManager.html

不要使用 ChainedTransactionManager 将回调附加到事务提交(提交前/提交后),而是注册 TransactionSynchronization 以在发生异常时使用简化的语义显式遵循事务清理。

您仍然可以自由地使用它,只是请记住,在未来的 Spring 版本中,该类将在某个时候被删除,并且如果不重构该部分就无法升级。

  • 是的,但是没有一个实际的例子来说明如何使用 TransactionSynchronization 来实现多个数据源提交...... (11认同)
  • 这实际上并不是一种改进,请注意,他们弃用了事务链的所有功能,因此“TransactionSynchronization”并不是替代品。请参考这个[票](https://github.com/spring-projects/spring-data-commons/issues/2232) (3认同)