如何使用不同传播的@Transactional超时属性

时间:2014-06-29 19:08:39

标签: spring transactions spring-3

我对@Transactional 超时属性的行为感到困惑

我有以下顺序

Main -> 
UserExecutionServiceImpl.executeRecordInvoice ->
ProcessInvoiceServiceImpl.recordInvoice ->
WarehouseServiceImpl.checkStockAvailability

要强制回滚异常超时设置为0。

如果 executeRecordInvoice @Transactional(timeout=0),则抛出异常并停止所有异常。它有意义

如果 executeRecordInvoice @Transactional recordInvoice @Transactional(timeout=0),则不会抛出异常。实际上,超时值已被忽略。

我可以假设因为事务真的以 executeRecordInvoice 开头,而且因为两种方法都默认为Propagation.Required,这意味着,第二种( recordInvoice )是在第一个( executeRecordInvoice )内考虑已经存在的正在运行的事务

更重要的是,我做了两个简单的实验:

  1. 如果 executeRecordInvoice @Transactional recordInvoice @Transactional(propagation.Propagation.REQUIRES_NEW, timeout=0),则会抛出异常。现在可行,因为交易始于 recordInvoice ,因此会考虑超时

  2. 直接从主要课程调用ProcessInvoiceServiceImpl.recordInvoice@Transactional(propagation.Propagation.REQUIRED, timeout=0)@Transactional(propagation.Propagation.REQUIRES_NEW, timeout=0),再次超时

  3. 直到这里,我很好,所有人都有道理。但是对于 WarehouseServiceImpl.checkStockAvailability 应用1和2,它不起作用:

    1. 如果 executeRecordInvoice recordInvoice @Transactional(因此默认情况下均为Propagation.REQUIRED)且 checkStockAvailability 有{ {1}}。例外情况是抛出!

    2. 直接从主要课程@Transactional(propagation.Propagation.REQUIRES_NEW, timeout=0)WarehouseServiceImpl.checkStockAvailability@Transactional(propagation.Propagation.REQUIRED, timeout=0),再次超时 考虑。

    3. 班级宣言

      @Transactional(propagation.Propagation.REQUIRES_NEW, timeout=0)

      欢迎任何想法或建议。

      Spring Framework 4.0.5

      谢谢。

      在做了Andrei的建议后,我有以下内容:

      @Service
      @Transactional
      @Scope("prototype")
      public class WarehouseServiceImpl implements WarehouseService {
      
          // Unique method implementation
          @Transactional(propagation = Propagation.REQUIRES_NEW, timeout=0)
          public boolean checkStockAvailability(Product product, BigDecimal quantity) {
      
              ...
      
          return true;
      
          }
      }
      

      在MainTest课程中

      @Transactional
      @Scope("prototype")
      @Service("processInvoiceService")
      public class ProcessInvoiceServiceImpl implements ProcessInvoiceService {
      
          @Override
          @Transactional(propagation = Propagation.REQUIRES_NEW, timeout=0)
          public void recordInvoice(InvoiceHeader invoiceHeader) {
      

      显示控制台,参与结果输出

      ProcessInvoiceService processInvoiceService = context.getBean(ProcessInvoiceService.class);
      
              try{
                  processInvoiceService.recordInvoice(invoiceHeader03);
              }
              catch(Exception e){
                  logger.error("ERROR ALFA: {}", e.getMessage());
              }
      

      出现错误消息预期如何..

      现在为其他班级

      Creating instance of bean 'processInvoiceService'
      20:16:57,320 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'productService'
      20:16:57,320 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'invoiceHeaderService'
      20:16:57,320 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'invoiceDetailService'
      20:16:57,321 DEBUG ctory.support.DefaultListableBeanFactory: 449 - Creating instance of bean 'warehouseServiceImpl'
      20:16:57,321 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
      20:16:57,321 DEBUG xy.InfrastructureAdvisorAutoProxyCreator: 593 - Creating implicit proxy for bean 'warehouseServiceImpl' with 0 common interceptors and 1 specific interceptors
      20:16:57,321 DEBUG amework.aop.framework.JdkDynamicAopProxy: 117 - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.manuel.jordan.model.service.support.impl.WarehouseServiceImpl@7b4c50bc]
      20:16:57,321 DEBUG ctory.support.DefaultListableBeanFactory: 477 - Finished creating instance of bean 'warehouseServiceImpl'
      20:16:57,322  INFO e.process.impl.ProcessInvoiceServiceImpl:  46 - ProcessInvoiceServiceImpl arg constructor
      20:16:57,322 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
      20:16:57,322 DEBUG xy.InfrastructureAdvisorAutoProxyCreator: 593 - Creating implicit proxy for bean 'processInvoiceService' with 0 common interceptors and 1 specific interceptors
      20:16:57,322 DEBUG amework.aop.framework.JdkDynamicAopProxy: 117 - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.manuel.jordan.model.service.process.impl.ProcessInvoiceServiceImpl@5884a914]
      20:16:57,322 DEBUG ctory.support.DefaultListableBeanFactory: 477 - Finished creating instance of bean 'processInvoiceService'
      20:16:57,322 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'transactionManager'
      20:16:57,322 DEBUG .datasource.DataSourceTransactionManager: 367 - Creating new transaction with name [com.manuel.jordan.model.service.process.impl.ProcessInvoiceServiceImpl.recordInvoice]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,timeout_0; ''
      20:16:57,322 DEBUG k.jdbc.datasource.SimpleDriverDataSource: 138 - Creating new JDBC Driver Connection to [jdbc:hsqldb:mem:testdb]
      20:16:57,323 DEBUG .datasource.DataSourceTransactionManager: 206 - Acquired Connection [org.hsqldb.jdbc.JDBCConnection@50378a4] for JDBC transaction
      20:16:57,323 DEBUG .datasource.DataSourceTransactionManager: 223 - Switching JDBC Connection [org.hsqldb.jdbc.JDBCConnection@50378a4] to manual commit
      20:16:57,323  INFO e.process.impl.ProcessInvoiceServiceImpl:  59 - ProcessInvoiceServiceImpl recordInvoice - start
      20:16:57,323 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'transactionManager'
      20:16:57,323 DEBUG .datasource.DataSourceTransactionManager: 472 - Participating in existing transaction
      20:16:57,323 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'transactionManager'
      20:16:57,323 DEBUG .datasource.DataSourceTransactionManager: 472 - Participating in existing transaction
      20:16:57,324 DEBUG g.springframework.jdbc.core.JdbcTemplate: 908 - Executing prepared SQL update
      20:16:57,324 DEBUG g.springframework.jdbc.core.JdbcTemplate: 627 - Executing prepared SQL statement [INSERT INTO invoiceheader(id, number, date, total) VALUES(?, ?, ?, ?)]
      20:16:57,324 DEBUG .datasource.DataSourceTransactionManager: 854 - Participating transaction failed - marking existing transaction as rollback-only
      20:16:57,324 DEBUG .datasource.DataSourceTransactionManager: 295 - Setting JDBC transaction [org.hsqldb.jdbc.JDBCConnection@50378a4] rollback-only
      20:16:57,324 DEBUG .datasource.DataSourceTransactionManager: 854 - Participating transaction failed - marking existing transaction as rollback-only
      20:16:57,325 DEBUG .datasource.DataSourceTransactionManager: 295 - Setting JDBC transaction [org.hsqldb.jdbc.JDBCConnection@50378a4] rollback-only
      20:16:57,325 DEBUG .datasource.DataSourceTransactionManager: 847 - Initiating transaction rollback
      20:16:57,325 DEBUG .datasource.DataSourceTransactionManager: 281 - Rolling back JDBC transaction on Connection [org.hsqldb.jdbc.JDBCConnection@50378a4]
      20:16:57,325 DEBUG .datasource.DataSourceTransactionManager: 324 - Releasing JDBC Connection [org.hsqldb.jdbc.JDBCConnection@50378a4] after transaction
      20:16:57,325 DEBUG ramework.jdbc.datasource.DataSourceUtils: 327 - Returning JDBC Connection to DataSource
      20:16:57,325 ERROR          com.manuel.jordan.main.MainTest:  93 - ERROR ALFA: Transaction timed out: deadline was Mon Jun 30 20:16:57 PET 2014
      20:16:57,325 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'transactionManager'
      

      在MainTest课程中

      @Service
      @Transactional
      @Scope("prototype")
      public class WarehouseServiceImpl implements WarehouseService {
      
          private static final Logger logger = LoggerFactory.getLogger(WarehouseServiceImpl.class);
      
          @Override
          @Transactional(propagation = Propagation.REQUIRES_NEW, timeout=0)
          public boolean checkStockAvailability(Product product, BigDecimal quantity) {
      

      显示控制台,参与结果输出

      WarehouseService warehouseService = context.getBean(WarehouseService.class);
      
              try{
                  logger.info("Pre");
                  boolean result = warehouseService.checkStockAvailability(product01, BigDecimal.ZERO);
                  logger.info("result: {}", result);
                  logger.info("Post");
              }
              catch(Exception e){
                  logger.error("ERROR BETA: {}", e.getMessage());
              }
      

      没有抛出错误的预期......

      奥米克

      新的更新代码:

      20:16:57,337 DEBUG ctory.support.DefaultListableBeanFactory: 449 - Creating instance of bean 'warehouseServiceImpl'
      20:16:57,337 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
      20:16:57,338 DEBUG xy.InfrastructureAdvisorAutoProxyCreator: 593 - Creating implicit proxy for bean 'warehouseServiceImpl' with 0 common interceptors and 1 specific interceptors
      20:16:57,338 DEBUG amework.aop.framework.JdkDynamicAopProxy: 117 - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.manuel.jordan.model.service.support.impl.WarehouseServiceImpl@23f5b5dc]
      20:16:57,338 DEBUG ctory.support.DefaultListableBeanFactory: 477 - Finished creating instance of bean 'warehouseServiceImpl'
      20:16:57,338  INFO          com.manuel.jordan.main.MainTest: 102 - Pre
      20:16:57,338 DEBUG ion.AnnotationTransactionAttributeSource: 108 - Adding transactional method 'WarehouseServiceImpl.checkStockAvailability' with attribute: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,timeout_0; ''
      20:16:57,338 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'transactionManager'
      20:16:57,339 DEBUG .datasource.DataSourceTransactionManager: 367 - Creating new transaction with name [com.manuel.jordan.model.service.support.impl.WarehouseServiceImpl.checkStockAvailability]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,timeout_0; ''
      20:16:57,339 DEBUG k.jdbc.datasource.SimpleDriverDataSource: 138 - Creating new JDBC Driver Connection to [jdbc:hsqldb:mem:testdb]
      20:16:57,339 DEBUG .datasource.DataSourceTransactionManager: 206 - Acquired Connection [org.hsqldb.jdbc.JDBCConnection@34bde49d] for JDBC transaction
      20:16:57,339 DEBUG .datasource.DataSourceTransactionManager: 223 - Switching JDBC Connection [org.hsqldb.jdbc.JDBCConnection@34bde49d] to manual commit
      20:16:57,339 DEBUG .datasource.DataSourceTransactionManager: 755 - Initiating transaction commit
      20:16:57,339 DEBUG .datasource.DataSourceTransactionManager: 266 - Committing JDBC transaction on Connection [org.hsqldb.jdbc.JDBCConnection@34bde49d]
      20:16:57,339 DEBUG .datasource.DataSourceTransactionManager: 324 - Releasing JDBC Connection [org.hsqldb.jdbc.JDBCConnection@34bde49d] after transaction
      20:16:57,339 DEBUG ramework.jdbc.datasource.DataSourceUtils: 327 - Returning JDBC Connection to DataSource
      20:16:57,339  INFO          com.manuel.jordan.main.MainTest: 104 - result: true
      20:16:57,339  INFO          com.manuel.jordan.main.MainTest: 105 - Post
      

      上面显示的代码对于两个项目是相同的,对于一个使用JdbcTemplate的代码,一切正常,抛出预期的错误,但是使用Hibernate的另一个项目不会抛出预期的错误。在结果输出下面。

      @Service
      @Transactional
      @Scope("prototype")
      public class WarehouseServiceImpl implements WarehouseService {
      
          private static final Logger logger = LoggerFactory.getLogger(WarehouseServiceImpl.class);
      
          private ProductService productService;
      
          @Autowired
          public WarehouseServiceImpl(ProductService productService){
              this.productService = productService;
          }
      
          @Override
          @Transactional(propagation = Propagation.REQUIRES_NEW, timeout=0)
          public boolean checkStockAvailability(Product product, BigDecimal quantity) {
      
              logger.info("Amount: {}", this.productService.getAmountProducts());
              ...     
              return true;
      
          }
      
      }
      

      有些线索? DataAccess当然存在......

1 个答案:

答案 0 :(得分:1)

查看您的第一个日志(与recordInvoicecheckStockAvailability的超时问题相关),这些确实表明正确应用了事务行为:在Java代码级别事务处理已启动并提交。日志的唯一区别在于,recordInvoice对数据库执行了实际查询,而checkStockAvailability没有这样的事情。

可能的答案是,如果数据库没有活动,则没有数据库级事务。您在java代码中拥有的内容反映在db级别。例如,如果您打开MySQL控制台并在表中插入内容,最后您需要提交以在DB中查看结果。

与您的第二个问题相关,您在一个测试中使用JdbcTemplate而另一个使用Hibernate(使用HibernateTransactionManager),查看source code for the Hibernate transaction似乎只有值严格更高考虑超过0。因此,一个简单的测试涉及将超时设置为一秒,而在事务方法checkStockAvailability中可以添加Thread.sleep(1500),这可以揭示超时的0秒值被忽略,解释测试结果。