Java 为什么Spring@Transactional成功回滚(SQL插入),但在(SQL更新)-多个数据源时失败

Java 为什么Spring@Transactional成功回滚(SQL插入),但在(SQL更新)-多个数据源时失败,java,hibernate,spring-boot,transactions,spring-data-jpa,Java,Hibernate,Spring Boot,Transactions,Spring Data Jpa,我有一个使用springboot&JPA的项目。API是使用REST公开的 我连接了两个不同的数据库(Mysql 8),并添加了用于池的Hikari。链式事务管理器用于在两个数据库中的任何一个出现故障时回滚这两个数据库 第一个问题:如果我将TMSDbConfig标记为@Primary,那么在辅助数据库UserProfileDbConfig中不会发生插入。只有一个transactionManager启动,可以插入TMSDbConfig 第二个问题:如果我将UserProfileDbConfig标记

我有一个使用springboot&JPA的项目。API是使用REST公开的

我连接了两个不同的数据库(Mysql 8),并添加了用于池的Hikari。链式事务管理器用于在两个数据库中的任何一个出现故障时回滚这两个数据库

第一个问题:如果我将TMSDbConfig标记为@Primary,那么在辅助数据库UserProfileDbConfig中不会发生插入。只有一个transactionManager启动,可以插入TMSDbConfig

第二个问题:如果我将UserProfileDbConfig标记为@Primary,那么上面的问题就解决了,现在我可以在DBs中插入,并且在插入失败时,它们也会回滚。但是,当我从DB(使用findByName())获取实体时,请做一些更改,并在第二个数据库失败时将其保留回去,第一个数据库永远不会回滚

我尝试过,@EnableTransactionManagement on MainApp,@ComponentScan@EntityScan

尝试在@Repository或@Component中添加注释。 还尝试将这些方法放入不同的bean中

什么都不管用

以下是配置:, 主要内容:

数据库配置

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.mycompany.chainedtransactionmanager.repository.db2",
        entityManagerFactoryRef = "db2EntityManagerFactory", transactionManagerRef = "db2PlatformTransactionManager")
public class UserProfileDbConfig {

    @Primary
    @Bean(name = "db2DataSource")
    @ConfigurationProperties(prefix = "spring.userprofile-datasource")
    public DataSource db2DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "db2EntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean db2EntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(db2DataSource())
                .packages("com.mycompany.chainedtransactionmanager.model.db2")
                .persistenceUnit("db2")
                .build();
    }

    @Primary
    @Bean(name = "db2PlatformTransactionManager")
    public PlatformTransactionManager db2PlatformTransactionManager(EntityManagerFactory db2EntityManagerFactory) {
        return new JpaTransactionManager(db2EntityManagerFactory);
    }
}
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.mycompany.chainedtransactionmanager.repository.pgsql",
        entityManagerFactoryRef = "pgsqlEntityManagerFactory", transactionManagerRef = "pgsqlPlatformTransactionManager")
public class TMSDbConfig {


    @Bean(name = "pgsqlDataSource")
    @ConfigurationProperties(prefix = "spring.tms-datasource")
    public DataSource pgsqlDataSource() {
        return DataSourceBuilder.create().build();
    }


    @Bean(name = "pgsqlEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean 
        pgsqlEntityManagerFactory(@Qualifier("pgsqlDataSource") DataSource 
        pgsqlDataSource, EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(pgsqlDataSource)
                .packages("com.mycompany.chainedtransactionmanager.model.pgsql")
                .persistenceUnit("pgsql")
                .build();
    }


    @Bean(name = "pgsqlPlatformTransactionManager")
    public PlatformTransactionManager pgsqlPlatformTransactionManager(@Qualifier("pgsqlEntityManagerFactory") EntityManagerFactory pgsqlEntityManagerFactory) {
        return new JpaTransactionManager(pgsqlEntityManagerFactory);
    }
}
另一个数据库配置

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.mycompany.chainedtransactionmanager.repository.db2",
        entityManagerFactoryRef = "db2EntityManagerFactory", transactionManagerRef = "db2PlatformTransactionManager")
public class UserProfileDbConfig {

    @Primary
    @Bean(name = "db2DataSource")
    @ConfigurationProperties(prefix = "spring.userprofile-datasource")
    public DataSource db2DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "db2EntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean db2EntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(db2DataSource())
                .packages("com.mycompany.chainedtransactionmanager.model.db2")
                .persistenceUnit("db2")
                .build();
    }

    @Primary
    @Bean(name = "db2PlatformTransactionManager")
    public PlatformTransactionManager db2PlatformTransactionManager(EntityManagerFactory db2EntityManagerFactory) {
        return new JpaTransactionManager(db2EntityManagerFactory);
    }
}
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.mycompany.chainedtransactionmanager.repository.pgsql",
        entityManagerFactoryRef = "pgsqlEntityManagerFactory", transactionManagerRef = "pgsqlPlatformTransactionManager")
public class TMSDbConfig {


    @Bean(name = "pgsqlDataSource")
    @ConfigurationProperties(prefix = "spring.tms-datasource")
    public DataSource pgsqlDataSource() {
        return DataSourceBuilder.create().build();
    }


    @Bean(name = "pgsqlEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean 
        pgsqlEntityManagerFactory(@Qualifier("pgsqlDataSource") DataSource 
        pgsqlDataSource, EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(pgsqlDataSource)
                .packages("com.mycompany.chainedtransactionmanager.model.pgsql")
                .persistenceUnit("pgsql")
                .build();
    }


    @Bean(name = "pgsqlPlatformTransactionManager")
    public PlatformTransactionManager pgsqlPlatformTransactionManager(@Qualifier("pgsqlEntityManagerFactory") EntityManagerFactory pgsqlEntityManagerFactory) {
        return new JpaTransactionManager(pgsqlEntityManagerFactory);
    }
}
连锁交易经理

@Configuration
public class TransactionManagerConfig {

    @Bean(name = "chainedTransactionManager")
    public ChainedTransactionManager transactionManager(
            @Qualifier("db2PlatformTransactionManager") PlatformTransactionManager db2PlatformTransactionManager,
            @Qualifier("pgsqlPlatformTransactionManager") PlatformTransactionManager pgsqlPlatformTransactionManager) {
        return new ChainedTransactionManager(db2PlatformTransactionManager,
                pgsqlPlatformTransactionManager);
    }
}
服务层插入代码,成功回滚

@Override
@Transactional(value = "chainedTransactionManager", rollbackFor = {Exception.class}, propagation = Propagation.REQUIRES_NEW)
public void saveService() {
    try {
        {//Insert code..


            DB2Test1 SecTable = new DB2Test1();
            SecTable.setName("LongTextToCreateSqlError");
            db2Repo.save(SecTable);

            DB1Test1 firstTable = new DB1Test1();
            firstTable.setName("acceptedText");
            db1Repo.save(firstTable);
        }
    } catch (Exception e) {
    }
@Override
    @Transactional(value = "chainedTransactionManager", rollbackFor = {Exception.class}, propagation = Propagation.REQUIRES_NEW)
    public void saveService() {
try {
    DB2Test1 SecTable = db2Repo.findByName("Jhon");
    SecTable.setName("LongTextToCreateFailed");

    try {
        db2Repo.save(SecTable);
    } catch (Exception e) {
        throw e;
    }
    DB1Test1 firstTable =  db1Repo.findByName("Jhon");
    firstTable.setName("AcceptedText");
    try {
        db1Repo.save(firstTable);
    } catch (Exception e) {
        throw e;
    }
} catch (Exception e) {
    throw e;
}
}
服务层更新代码,回滚失败

@Override
@Transactional(value = "chainedTransactionManager", rollbackFor = {Exception.class}, propagation = Propagation.REQUIRES_NEW)
public void saveService() {
    try {
        {//Insert code..


            DB2Test1 SecTable = new DB2Test1();
            SecTable.setName("LongTextToCreateSqlError");
            db2Repo.save(SecTable);

            DB1Test1 firstTable = new DB1Test1();
            firstTable.setName("acceptedText");
            db1Repo.save(firstTable);
        }
    } catch (Exception e) {
    }
@Override
    @Transactional(value = "chainedTransactionManager", rollbackFor = {Exception.class}, propagation = Propagation.REQUIRES_NEW)
    public void saveService() {
try {
    DB2Test1 SecTable = db2Repo.findByName("Jhon");
    SecTable.setName("LongTextToCreateFailed");

    try {
        db2Repo.save(SecTable);
    } catch (Exception e) {
        throw e;
    }
    DB1Test1 firstTable =  db1Repo.findByName("Jhon");
    firstTable.setName("AcceptedText");
    try {
        db1Repo.save(firstTable);
    } catch (Exception e) {
        throw e;
    }
} catch (Exception e) {
    throw e;
}
}
在日志中我可以看到,在插入的情况下,entityManager直到两个db操作都成功后才关闭

但如果在运行第一个更新查询后进行更新,entityManager将关闭。 我无法理解这种行为, Insert case已成功回滚,但在更新时未回滚。如果它与托管bean相关联,那么插入代码和更新代码之间的区别是什么


谢谢大家的问候

解决方案

找到了一个解决方案,也许它可以为搜索这个的人节省几天时间

我从JPA simple.save()方法切换到.saveAndFlush(),所有的测试用例要么都在DB中持久化,要么都回滚通过


干杯

您好,这是因为在调用save()时,hibernate会话不会与DB(flush)同步