springboot2事务注解不起作用

e7arh2l6  于 2021-07-22  发布在  Java
关注(0)|答案(0)|浏览(247)

关于@transactional的springboot2.3.8.release实现的问题。需求是实现分布式事务,该事务写入postgresql和artemis队列的示例。如果一个提交失败,那么另一个也应该失败。我们使用atomikos作为jta事务管理器。
我想我已经实现了我需要的一切,但显然没有。当我在服务代码中抛出一个异常来测试回滚功能时,它显然不起作用:即使在我在服务代码中抛出一个异常之后,消息也会被写入artemis。
任何诊断和修复方面的帮助都将不胜感激。如果需要任何额外的细节,请告诉我。
具体实施情况如下:
Spring启动应用:

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.boot.CommandLineRunner;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  6. import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
  7. import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
  8. import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
  9. import org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration;
  10. import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
  11. import org.springframework.context.ConfigurableApplicationContext;
  12. import xxx.xxx.Users;
  13. import xxx.xxx.TransactionServiceImpl;
  14. @SpringBootApplication
  15. (
  16. exclude = {
  17. DataSourceAutoConfiguration.class,
  18. HibernateJpaAutoConfiguration.class,
  19. DataSourceTransactionManagerAutoConfiguration.class,
  20. JmsAutoConfiguration.class,
  21. ActiveMQAutoConfiguration.class,
  22. ArtemisAutoConfiguration.class
  23. }
  24. )
  25. public class BApplication implements CommandLineRunner
  26. {
  27. public static void main(String[] args) throws Exception
  28. {
  29. // SpringApplication.run(BoilerplateApplication.class, args);
  30. ConfigurableApplicationContext ctx = SpringApplication.run(BApplication.class, args);
  31. System.in.read();
  32. ctx.close();
  33. }
  34. @Autowired
  35. TransactionServiceImpl tsi;
  36. @Override
  37. public void run(String... args) throws Exception
  38. {
  39. Users user = new Users();
  40. user.setFirstName("Moe");
  41. user.setGender("M");
  42. user.setLastName("Moe");
  43. tsi.save(user);
  44. }
  45. }

以下是jta配置:
jta配置

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import javax.jms.ConnectionFactory;
  4. import javax.jms.JMSException;
  5. import javax.sql.DataSource;
  6. import javax.transaction.SystemException;
  7. import javax.transaction.UserTransaction;
  8. import java.util.Properties;
  9. import javax.annotation.PostConstruct;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.orm.jpa.JpaVendorAdapter;
  12. import org.springframework.context.annotation.Primary;
  13. import org.springframework.context.annotation.DependsOn;
  14. import org.springframework.beans.factory.annotation.Value;
  15. import org.springframework.context.annotation.Configuration;
  16. import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
  17. import com.atomikos.icatch.config.UserTransactionService;
  18. import com.atomikos.icatch.config.UserTransactionServiceImp;
  19. import com.atomikos.icatch.jta.UserTransactionImp;
  20. import com.atomikos.icatch.jta.UserTransactionManager;
  21. import com.atomikos.jdbc.AtomikosDataSourceBean;
  22. import com.atomikos.jms.AtomikosConnectionFactoryBean;
  23. import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
  24. import org.postgresql.xa.PGXADataSource;
  25. @Configuration("jtaConfig")
  26. public class JtaConfig
  27. {
  28. private static final Logger appLogger = LoggerFactory.getLogger(JtaConfig.class);
  29. @Value("${amq.broker.url}")
  30. private String brokerUrl;
  31. @Value("${amq.broker.username}")
  32. private String brokerUsername;
  33. @Value("${amq.broker.password}")
  34. private String brokerPassword;
  35. @Value("${postgresql.datasource.url}")
  36. String dataSourceUrl;
  37. @Value("${postgresql.datasource.username}")
  38. String dsUsername;
  39. @Value("${postgresql.datasource.password}")
  40. String dsPassword;
  41. @Value("${postgresql.datasource.driver.classname}")
  42. String dsClassName;
  43. @Value("${postgresql.initial.connections}")
  44. int initialDSConnections;
  45. @Value("${postgresql.max.connections}")
  46. int maxDSConnections;
  47. @Bean(initMethod = "init", destroyMethod = "shutdownForce")
  48. public UserTransactionService userTransactionService()
  49. {
  50. Properties atProps = new Properties();
  51. atProps.put("com.atomikos.icatch.service", "com.atomikos.icatch.standalone.UserTransactionServiceFactory");
  52. return new UserTransactionServiceImp(atProps);
  53. }
  54. @Bean (initMethod = "init", destroyMethod = "close")
  55. @DependsOn("userTransactionService")
  56. public UserTransactionManager atomikosTransactionManager()
  57. {
  58. UserTransactionManager utm = new UserTransactionManager();
  59. utm.setStartupTransactionService(false);
  60. utm.setForceShutdown(true);
  61. return utm;
  62. }
  63. @Bean
  64. @DependsOn("userTransactionService")
  65. public UserTransaction userTransaction()
  66. {
  67. UserTransactionImp ut = new UserTransactionImp();
  68. try
  69. {
  70. ut.setTransactionTimeout(1000);
  71. }
  72. catch (SystemException _e)
  73. {
  74. appLogger.error("Configuration exception.", _e);
  75. return null;
  76. }
  77. return ut;
  78. }
  79. @Bean
  80. public Properties hibernateProperties()
  81. {
  82. Properties hibernateProp = new Properties();
  83. hibernateProp.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
  84. hibernateProp.put("hibernate.hbm2ddl.auto", "create-drop");
  85. hibernateProp.put("hibernate.show_sql", true);
  86. hibernateProp.put("hibernate.max_fetch_depth", 3);
  87. hibernateProp.put("hibernate.jdbc.batch_size", 10);
  88. hibernateProp.put("hibernate.jdbc.fetch_size", 50);
  89. return hibernateProp;
  90. }
  91. @Bean
  92. public JpaVendorAdapter jpaVendorAdapter()
  93. {
  94. return new HibernateJpaVendorAdapter();
  95. }
  96. @Primary
  97. @Bean(name = "pgDataSource1", initMethod = "init", destroyMethod = "close")
  98. public DataSource pgDataSource1()
  99. {
  100. PGXADataSource primaryXaDataSource = new PGXADataSource();
  101. primaryXaDataSource.setUrl(dataSourceUrl);
  102. primaryXaDataSource.setUser(dsUsername);
  103. primaryXaDataSource.setPassword(dsPassword);
  104. AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
  105. xaDataSource.setXaDataSource(primaryXaDataSource);
  106. xaDataSource.setUniqueResourceName("primaryXaDs1");
  107. xaDataSource.setMinPoolSize(initialDSConnections);
  108. xaDataSource.setMaxPoolSize(maxDSConnections);
  109. return xaDataSource;
  110. }
  111. @Primary
  112. @Bean(name = "jmsConnectionFactory", initMethod = "init", destroyMethod = "close")
  113. public ConnectionFactory connectionFactory()
  114. {
  115. AtomikosConnectionFactoryBean atomikosConnectionFactoryBean = new AtomikosConnectionFactoryBean();
  116. ActiveMQConnectionFactory activeMqXaConnectionFactory = new ActiveMQConnectionFactory();
  117. try
  118. {
  119. activeMqXaConnectionFactory.setBrokerURL(brokerUrl);
  120. activeMqXaConnectionFactory.setUser(brokerUsername);
  121. activeMqXaConnectionFactory.setPassword(brokerPassword);
  122. atomikosConnectionFactoryBean.setUniqueResourceName("jmsXAConnectionFactory");
  123. atomikosConnectionFactoryBean.setLocalTransactionMode(false);
  124. atomikosConnectionFactoryBean.setXaConnectionFactory(activeMqXaConnectionFactory);
  125. }
  126. catch (JMSException _e)
  127. {
  128. appLogger.info("JMS Configuration Error: " + _e);
  129. _e.printStackTrace();
  130. }
  131. return atomikosConnectionFactoryBean;
  132. }
  133. @PostConstruct
  134. public void postConstructDetails()
  135. {
  136. appLogger.info("Post Construct Start: JtaConfig.");
  137. appLogger.info(" - JMS: Artemis URL: {}", brokerUrl);
  138. appLogger.info(" - Artemis Username: {}", brokerUsername);
  139. appLogger.info(" - Artemis Password: {}", brokerPassword);
  140. appLogger.info(" - DS: PostgreSQL URL: {}", dataSourceUrl);
  141. appLogger.info(" - DS: PostgreSQL Username: {}", dsUsername);
  142. appLogger.info(" - DS: PostgreSQL Password: {}", dsPassword);
  143. appLogger.info(" - DS: PostgreSQL Min Conn: {}", initialDSConnections);
  144. appLogger.info(" - DS: PostgreSQL Max Conn: {}", maxDSConnections);
  145. appLogger.info("Post Construct End: JtaConfig.");
  146. appLogger.info(" ");
  147. }
  148. }

以下是服务配置的实现:
服务配置:

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.jms.core.JmsTemplate;
  6. import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
  7. import org.springframework.context.annotation.ComponentScan;
  8. import org.springframework.context.annotation.Configuration;
  9. import org.springframework.transaction.jta.JtaTransactionManager;
  10. import org.springframework.transaction.PlatformTransactionManager;
  11. import org.springframework.transaction.annotation.EnableTransactionManagement;
  12. import javax.annotation.PostConstruct;
  13. import javax.persistence.EntityManagerFactory;
  14. @Configuration
  15. @EnableTransactionManagement
  16. @ComponentScan(basePackages = "xxx.xxx.service")
  17. public class ServicesConfig
  18. {
  19. private Logger appLogger = LoggerFactory.getLogger(ServicesConfig.class);
  20. @Autowired
  21. JtaConfig jtaConfig;
  22. @Bean(name = "xaJmsTemplate")
  23. public JmsTemplate jmsTemplate()
  24. {
  25. JmsTemplate jmsTemplate = new JmsTemplate();
  26. jmsTemplate.setConnectionFactory(jtaConfig.connectionFactory());
  27. jmsTemplate.setPubSubDomain(false);
  28. return jmsTemplate;
  29. }
  30. @Bean(name = "entityManangerFactory")
  31. public EntityManagerFactory entityManagerFactory()
  32. {
  33. LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
  34. factoryBean.setPackagesToScan("xxx.xxx.model");
  35. factoryBean.setDataSource(jtaConfig.pgDataSource1());
  36. factoryBean.setJpaProperties(jtaConfig.hibernateProperties());
  37. factoryBean.setPersistenceUnitName("entityManagerFactoryA");
  38. factoryBean.setJpaVendorAdapter(jtaConfig.jpaVendorAdapter());
  39. factoryBean.afterPropertiesSet();
  40. return factoryBean.getNativeEntityManagerFactory();
  41. }
  42. @Bean(name = "transactionManager")
  43. public PlatformTransactionManager transactionManager()
  44. {
  45. JtaTransactionManager ptm = new JtaTransactionManager();
  46. ptm.setTransactionManager(jtaConfig.atomikosTransactionManager());
  47. ptm.setUserTransaction(jtaConfig.userTransaction());
  48. return ptm;
  49. }
  50. @PostConstruct
  51. public void postConstructDetails()
  52. {
  53. appLogger.info("Post Construct Start: ServicesConfig.");
  54. appLogger.info(" - JMS: Artemis URL: {}", jtaConfig);
  55. appLogger.info(" - JMS Template: {}", jmsTemplate());
  56. appLogger.info("Post Construct End: ServicesConfig.");
  57. appLogger.info(" ");
  58. }
  59. }

以下是服务实现:
事务服务模板

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  5. import org.springframework.jms.core.JmsTemplate;
  6. import org.springframework.stereotype.Service;
  7. import org.springframework.transaction.annotation.Transactional;
  8. import xxx.xxx.Users;
  9. @Service("transactionService")
  10. @Transactional
  11. public class TransactionServiceImpl implements TransactionServiceIntf
  12. {
  13. private static final Logger appLogger = LoggerFactory.getLogger(TransactionServiceImpl.class);
  14. @Autowired
  15. @Qualifier("xaJmsTemplate")
  16. JmsTemplate jmsTemplate;
  17. @Override
  18. public Users save(Users _user)
  19. {
  20. appLogger.info("TransactionServiceImpl: save: Entered.");
  21. Users user = _user;
  22. try
  23. {
  24. if(user == null)
  25. {
  26. appLogger.info("User: Null.");
  27. }
  28. else
  29. {
  30. if(jmsTemplate == null)
  31. {
  32. appLogger.info("JMS Template: Null.");
  33. }
  34. else
  35. {
  36. appLogger.info("JMS Template: Saving.");
  37. jmsTemplate.convertAndSend("crequests", user);
  38. }
  39. }
  40. // The rollback should happen with the exception.
  41. throw new Exception();
  42. }
  43. catch(Exception _e)
  44. {
  45. appLogger.error("Catching exception: " + _e);
  46. }
  47. appLogger.info("TransactionServiceImpl: save: Exiting.");
  48. return user;
  49. }
  50. }

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题