Spring boot springboot jta事务回滚不工作

Spring boot springboot jta事务回滚不工作,spring-boot,spring-data,jta,Spring Boot,Spring Data,Jta,我想使用JTA(使用atomikos)配置跨数据库执行事务 我有下面的代码,我想在一个事务中执行。但是,当我运行应用程序时,它会保存entityObject1和update eventObject2,并且在我运行l.intValue()语句时引发异常时不会回滚。下面是我在配置JTA时使用的所有代码 我遗漏了什么吗?谁能帮忙吗 public void testJTATRansaction() { service1.saveEvent1(eventObject1); service2

我想使用JTA(使用atomikos)配置跨数据库执行事务

我有下面的代码,我想在一个事务中执行。但是,当我运行应用程序时,它会保存entityObject1和update eventObject2,并且在我运行l.intValue()语句时引发异常时不会回滚。下面是我在配置JTA时使用的所有代码

我遗漏了什么吗?谁能帮忙吗

public void testJTATRansaction() {
    service1.saveEvent1(eventObject1);
    service2.updateEvent2(eventObject2);
}           
service1中的saveEvent1方法:

@Transactional(propagation=Propagation.REQUIRED, rollbackFor = Exception.class)
public int saveEvent1(Object eventObject1) {
    return repository1.save(eventObject1);
}
service2中的updateEvent2方法:

@Transactional(propagation=Propagation.REQUIRED, rollbackFor = Exception.class)
public int updateEvent2(Object eventObject2) {
    int i = l.intValue();   //l is null object, to throw error
    return repository2.updateEvent2(eventObject2);
}
我正在使用repository1中的默认保存方法(JPARepository保存方法)

repository2类中的updateEvent2方法:

@Modifying
@Transactional(propagation=Propagation.REQUIRED, rollbackFor = Exception.class)
@Query(UPDATE_EVENTS)
public int updateEvent2(
          @Param(value = "eventObject2") Object eventObject2);
我正在使用spring boot应用程序类初始化我的应用程序:

@SpringBootApplication
@ComponentScan("com.cbc.event")
@EnableTransactionManagement
public class RatingDaemonApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(RatingDaemonApplication.class);
    }
}
我有以下JTA配置:

@Configuration
@ComponentScan
@EnableTransactionManagement
public class JTATransactionConfig {

@Bean
public JpaVendorAdapter jpaVendorAdapter() {
    HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
    hibernateJpaVendorAdapter.setShowSql(true);
    hibernateJpaVendorAdapter.setGenerateDdl(true);
    hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
    return hibernateJpaVendorAdapter;
}

@Bean(name = "userTransaction")
public UserTransaction userTransaction() throws Throwable {
    UserTransactionImp userTransactionImp = new UserTransactionImp();
    userTransactionImp.setTransactionTimeout(10000);
    return userTransactionImp;
}

@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 = "transactionManager")
@DependsOn({ "userTransaction", "atomikosTransactionManager" })
public PlatformTransactionManager transactionManager() throws Throwable {
    UserTransaction userTransaction = userTransaction();

    AtomikosJtaPlatform.transaction = userTransaction;

    TransactionManager atomikosTransactionManager = atomikosTransactionManager();
    return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
}
}

数据源配置为:

@Configuration
@DependsOn("transactionManager")
@PropertySource({"classpath:application.properties"})
@EnableJpaRepositories(basePackages = {"com.cbc.repository"}, 
    transactionManagerRef="transactionManager", entityManagerFactoryRef = "entityMF")
public class dataSourceConfiguration {

    @Autowired
    Environment env;

    @Autowired
    JpaVendorAdapter jpaVendorAdapter;

    public DataSource eventsDS() {

        AtomikosDataSourceBean xaDS = new AtomikosDataSourceBean();
        xaDS.setXaDataSourceClassName(env.getProperty(DRIVER_CLASS_NAME));
        xaDS.setXaDataSource(getMysqlXADataSource());       
        xaDS.setUniqueResourceName("DS");
        xaDS.setMaxPoolSize(3);
        return xaDS;
    }

    private MysqlXADataSource getMysqlXADataSource() {
        MysqlXADataSource ds = new MysqlXADataSource();
        ds.setPinGlobalTxToPhysicalConnection(true);
        ds.setURL(env.getProperty(URL));
        ds.setUser(env.getProperty(USER));
        ds.setPassword(env.getProperty(PASSWORD));
        return ds;
    }

    @Bean(name="entityMF")
    public LocalContainerEntityManagerFactoryBean importedEventsEntityMF() {
        Map<String, Object> properties = new HashMap<>();
        properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
        properties.put("javax.persistence.transactionType", "JTA");

        LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
        entityManager.setJtaDataSource(eventsDS());
        entityManager.setJpaVendorAdapter(jpaVendorAdapter);
        entityManager.setPackagesToScan("com.cbc.events");
        entityManager.setPersistenceUnitName("persistenceUnit");
        entityManager.setJpaPropertyMap(properties);
        return entityManager;
    }
}

这来自spring文档

当需要传播设置时,将为应用该设置的每个方法创建一个逻辑事务范围。每个这样的逻辑事务作用域都可以单独确定仅回滚状态,外部事务作用域在逻辑上独立于内部事务作用域。当然,如果是标准的必要行为,所有这些作用域都将映射到同一个物理事务。因此,内部事务作用域中设置的仅回滚标记确实会影响外部事务实际提交的机会(正如您所期望的那样)

但是,在内部事务作用域设置仅回滚标记的情况下,外部事务尚未决定回滚本身,因此回滚(由内部事务作用域静默触发)是意外的。此时会引发相应的UnexpectedRollbackException。这是预期的行为,因此事务的调用方永远不会被误导,以为提交是在实际上没有执行的情况下执行的因此,如果内部事务(外部调用方不知道)以静默方式将事务标记为仅回滚,则外部调用方仍然调用提交。外部调用方需要接收一个意外的回滚异常,以清楚地指示执行了回滚。

尝试按如下所示更改方法声明并尝试一下

public int saveEvent1(Object eventObject1)引发意外的回滚异常

public int updateEvent2(对象eventObject2)引发意外的回滚异常

为了避免这种情况,最好在其中一个服务类或完全不同的服务类中使用单独的方法,并使用事务注释一次性调用这两个存储库操作


另外,当您使用事务注释对服务方法进行注释时,则不需要对存储库方法进行注释,与事务相关的注释越多,解决问题就越复杂。

使用h2数据源,分布式事务就成功了。 但是使用mysql数据源,测试失败。 (1) 首先怀疑atomikos不支持MysqlXADataSource好。 (2) 第二,认为JPA和hibernate不支持JTA那么好

然后我就可以使用jdbc了

@Configuration
public class ArticleConfigure {
    @ConfigurationProperties("second.datasource")
    @Bean(name="articleDataSourceProperties")
    public DataSourceProperties secondDataSourceProperties() {
        return new DataSourceProperties();
    }


    //@Bean(name = "articleDataSource")
    @Bean(name = "articleDataSource")
    public DataSource articleDataSource() {

        MysqlXADataSource mdatasource = new MysqlXADataSource();
        mdatasource.setUrl(secondDataSourceProperties().getUrl());
        mdatasource.setUser(secondDataSourceProperties().getUsername());
        mdatasource.setPassword(secondDataSourceProperties().getPassword());

        /*JdbcDataSource h2XaDataSource = new JdbcDataSource();
        h2XaDataSource.setURL(secondDataSourceProperties().getUrl());*/

        //atomikos datasource configure
        com.atomikos.jdbc.AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mdatasource);

        xaDataSource.setMaxPoolSize(30);
        xaDataSource.setUniqueResourceName("axds1");

        return xaDataSource;
    }


     @Bean(name = "twojdbcTemplate")
     public JdbcTemplate twojdbcTemplate() {

         return new JdbcTemplate(articleDataSource());
     }




}
TransactionConfig

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages="cn.crazychain")
public class TransactionConfig {



    @Bean(name = "userTransaction")
    public UserTransaction userTransaction() throws Throwable {
        UserTransactionImp userTransactionImp = new UserTransactionImp();
        userTransactionImp.setTransactionTimeout(10000);
        //return new BitronixTransactionManager();
        return userTransactionImp;
    }


    @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
    //@Bean(name = "atomikosTransactionManager")
    public TransactionManager atomikosTransactionManager() throws Throwable {
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        userTransactionManager.setForceShutdown(false);

        //return TransactionManagerServices.getTransactionManager();
        return userTransactionManager;
    }

    @Bean(name = "customerJtaTransactionManager")
    @DependsOn({ "userTransaction", "atomikosTransactionManager" })
    public PlatformTransactionManager transactionManager() throws Throwable {
        UserTransaction userTransaction = userTransaction();

        TransactionManager atomikosTransactionManager = atomikosTransactionManager();

        return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
    }

}
是否在hibernate jpa中有错误。 结论是JTA可以很好地与jdbc和AtomikosDataSourceBean配合使用。 源代码引用开放源代码项目是 我的全部源代码是
.

只有在使用JNDI时,JTA事务管理器才会工作。只有当数据源bean位于Java/Web容器中而不是应用程序中时,JTA tx manager才会侦听数据源并将其置于事务之下。容器

您需要使用JNDI让JTA工作,或者开始使用JPA事务管理器。
JTA事务管理器主要用于分布式事务,并且容易发生事务回滚失败。

在两个服务调用事务边界以外的事务后引发异常。对不起,我的错误,编辑了问题。service2类的updateEvent2方法中引发异常。还是一样的问题。我看到service1方法插入了一条记录,即使service2方法在事务期间抛出异常。它们看起来应该在service2.update回滚时提交第一个。您将看到插入的记录。@AndriySlobodyanyk,但我提到了@Transactional(propagation=propagation.REQUIRED,rollboor=Exception.class),所以两者应该在同一个事务中。关于信息,这两个事务都发生在不同的数据库中(这就是我在Atomikos中使用XA事务的原因)。AFAI知道如果我使用propagation=propagation.REQUIRED,那么在执行该方法时应该使用相同的事务。事务边界是带注释的方法。将两个事务粘合在一起的唯一方法是在testJTATRansaction上使用@Transactional。我猜这是Spring管理的测试,因为您在其中有自动连线服务,不是吗?顺便说一句,Propagation.required是默认值,rollbackFor属性仅用于已检查的异常,包括NPE在内的运行时异常也会被提及。为了确保在后台执行的操作,请打开org.springframework.transactional的调试日志
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages="cn.crazychain")
public class TransactionConfig {



    @Bean(name = "userTransaction")
    public UserTransaction userTransaction() throws Throwable {
        UserTransactionImp userTransactionImp = new UserTransactionImp();
        userTransactionImp.setTransactionTimeout(10000);
        //return new BitronixTransactionManager();
        return userTransactionImp;
    }


    @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
    //@Bean(name = "atomikosTransactionManager")
    public TransactionManager atomikosTransactionManager() throws Throwable {
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        userTransactionManager.setForceShutdown(false);

        //return TransactionManagerServices.getTransactionManager();
        return userTransactionManager;
    }

    @Bean(name = "customerJtaTransactionManager")
    @DependsOn({ "userTransaction", "atomikosTransactionManager" })
    public PlatformTransactionManager transactionManager() throws Throwable {
        UserTransaction userTransaction = userTransaction();

        TransactionManager atomikosTransactionManager = atomikosTransactionManager();

        return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
    }

}