不同传播机制下,@Transactional的超时属性如何工作

4

我对 @Transactional 的 timeout 属性的行为感到困惑。

我有以下序列:

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),同样会考虑超时时间

到这里为止,一切都很好,并且都是有意义的。但将1和2应用到 WarehouseServiceImpl.checkStockAvailability 上时,它却不起作用:

  1. 如果 executeRecordInvoicerecordInvoice 都具有 @Transactional(因此默认为 Propagation.REQUIRED),而 checkStockAvailability 具有 @Transactional(propagation.Propagation.REQUIRES_NEW, timeout=0)。则不会抛出异常!

  2. 从主类直接调用 WarehouseServiceImpl.checkStockAvailability,它具有 @Transactional(propagation.Propagation.REQUIRED, timeout=0)@Transactional(propagation.Propagation.REQUIRES_NEW, timeout=0),同样不会考虑超时时间

类声明

@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;

    }
}

欢迎提出任何想法和建议。

Spring Framework 4.0.5

谢谢。

在执行Andrei的建议后,我得到了以下结果:

@Transactional
@Scope("prototype")
@Service("processInvoiceService")
public class ProcessInvoiceServiceImpl implements ProcessInvoiceService {

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, timeout=0)
    public void recordInvoice(InvoiceHeader invoiceHeader) {

在MainTest类中

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'

错误信息如预期般出现。
现在轮到另一个类。
@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) {

在MainTest类中

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

错误未按预期抛出。

Omicron

新的更新代码:

@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;

    }

}

上面展示的代码对于两个项目都是相同的。在使用JdbcTemplate的项目中,一切正常,并抛出了预期的错误,但在另一个使用Hibernate的项目中却没有抛出预期的错误。以下是输出结果。
08:27:06,782  INFO          com.manuel.jordan.main.MainTest: 102 - Pre
08:27:06,782 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'transactionManager'
08:27:06,782 DEBUG m.hibernate4.HibernateTransactionManager: 367 - Creating new transaction with name [com.manuel.jordan.model.service.support.impl.WarehouseServiceImpl.checkStockAvailability]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,timeout_0; ''
08:27:06,783 DEBUG m.hibernate4.HibernateTransactionManager: 417 - Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@57ce634f updates=org.hibernate.engine.spi.ExecutableList@b8a7e43 deletions=org.hibernate.engine.spi.ExecutableList@35835fa orphanRemovals=org.hibernate.engine.spi.ExecutableList@56f71edb collectionCreations=org.hibernate.engine.spi.ExecutableList@7207cb51 collectionRemovals=org.hibernate.engine.spi.ExecutableList@2a27cb34 collectionUpdates=org.hibernate.engine.spi.ExecutableList@6892cc6f collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@6fd1660 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
08:27:06,783 DEBUG m.hibernate4.HibernateTransactionManager: 427 - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@57ce634f updates=org.hibernate.engine.spi.ExecutableList@b8a7e43 deletions=org.hibernate.engine.spi.ExecutableList@35835fa orphanRemovals=org.hibernate.engine.spi.ExecutableList@56f71edb collectionCreations=org.hibernate.engine.spi.ExecutableList@7207cb51 collectionRemovals=org.hibernate.engine.spi.ExecutableList@2a27cb34 collectionUpdates=org.hibernate.engine.spi.ExecutableList@6892cc6f collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@6fd1660 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
08:27:06,783 DEBUG gine.jdbc.internal.LogicalConnectionImpl: 226 - Obtaining JDBC connection
08:27:06,783 DEBUG k.jdbc.datasource.SimpleDriverDataSource: 138 - Creating new JDBC Driver Connection to [jdbc:hsqldb:mem:testdb]
08:27:06,783 DEBUG gine.jdbc.internal.LogicalConnectionImpl: 232 - Obtained JDBC connection
08:27:06,783 DEBUG .transaction.spi.AbstractTransactionImpl: 160 - begin
08:27:06,783 DEBUG ransaction.internal.jdbc.JdbcTransaction:  69 - initial autocommit status: true
08:27:06,783 DEBUG ransaction.internal.jdbc.JdbcTransaction:  71 - disabling autocommit
08:27:06,784 DEBUG m.hibernate4.HibernateTransactionManager: 488 - Exposing Hibernate transaction as JDBC transaction [org.hsqldb.jdbc.JDBCConnection@4a6c18ad]
08:27:06,784 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'transactionManager'
08:27:06,784 DEBUG m.hibernate4.HibernateTransactionManager: 362 - Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@57ce634f updates=org.hibernate.engine.spi.ExecutableList@b8a7e43 deletions=org.hibernate.engine.spi.ExecutableList@35835fa orphanRemovals=org.hibernate.engine.spi.ExecutableList@56f71edb collectionCreations=org.hibernate.engine.spi.ExecutableList@7207cb51 collectionRemovals=org.hibernate.engine.spi.ExecutableList@2a27cb34 collectionUpdates=org.hibernate.engine.spi.ExecutableList@6892cc6f collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@6fd1660 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
08:27:06,784 DEBUG m.hibernate4.HibernateTransactionManager: 472 - Participating in existing transaction
08:27:06,784 DEBUG ctory.support.DefaultListableBeanFactory: 249 - Returning cached instance of singleton bean 'transactionManager'
08:27:06,784 DEBUG m.hibernate4.HibernateTransactionManager: 362 - Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@57ce634f updates=org.hibernate.engine.spi.ExecutableList@b8a7e43 deletions=org.hibernate.engine.spi.ExecutableList@35835fa orphanRemovals=org.hibernate.engine.spi.ExecutableList@56f71edb collectionCreations=org.hibernate.engine.spi.ExecutableList@7207cb51 collectionRemovals=org.hibernate.engine.spi.ExecutableList@2a27cb34 collectionUpdates=org.hibernate.engine.spi.ExecutableList@6892cc6f collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@6fd1660 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
08:27:06,784 DEBUG m.hibernate4.HibernateTransactionManager: 472 - Participating in existing transaction
08:27:06,785 DEBUG                        org.hibernate.SQL: 109 - select count(*) as col_0_0_ from product product0_
08:27:06,785 DEBUG              org.hibernate.loader.Loader: 951 - Result set row: 0
08:27:06,786 DEBUG              org.hibernate.loader.Loader:1485 - Result row: 
08:27:06,786  INFO ervice.support.impl.WarehouseServiceImpl:  45 - Amount: 6
08:27:06,786 DEBUG m.hibernate4.HibernateTransactionManager: 755 - Initiating transaction commit
08:27:06,786 DEBUG m.hibernate4.HibernateTransactionManager: 551 - Committing Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@57ce634f updates=org.hibernate.engine.spi.ExecutableList@b8a7e43 deletions=org.hibernate.engine.spi.ExecutableList@35835fa orphanRemovals=org.hibernate.engine.spi.ExecutableList@56f71edb collectionCreations=org.hibernate.engine.spi.ExecutableList@7207cb51 collectionRemovals=org.hibernate.engine.spi.ExecutableList@2a27cb34 collectionUpdates=org.hibernate.engine.spi.ExecutableList@6892cc6f collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@6fd1660 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
08:27:06,786 DEBUG .transaction.spi.AbstractTransactionImpl: 175 - committing
08:27:06,786 DEBUG ransaction.internal.jdbc.JdbcTransaction: 113 - committed JDBC Connection
08:27:06,786 DEBUG ransaction.internal.jdbc.JdbcTransaction: 126 - re-enabling autocommit
08:27:06,787 DEBUG m.hibernate4.HibernateTransactionManager: 633 - Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@57ce634f updates=org.hibernate.engine.spi.ExecutableList@b8a7e43 deletions=org.hibernate.engine.spi.ExecutableList@35835fa orphanRemovals=org.hibernate.engine.spi.ExecutableList@56f71edb collectionCreations=org.hibernate.engine.spi.ExecutableList@7207cb51 collectionRemovals=org.hibernate.engine.spi.ExecutableList@2a27cb34 collectionUpdates=org.hibernate.engine.spi.ExecutableList@6892cc6f collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@6fd1660 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction
08:27:06,787 DEBUG gine.jdbc.internal.LogicalConnectionImpl: 246 - Releasing JDBC connection
08:27:06,787 DEBUG gine.jdbc.internal.LogicalConnectionImpl: 264 - Released JDBC connection
08:27:06,787  INFO          com.manuel.jordan.main.MainTest: 104 - result: true
08:27:06,787  INFO          com.manuel.jordan.main.MainTest: 105 - Post

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

谢谢Andrei,肯定有些奇怪的地方,我将在这个周末进行检查。谢谢! - Manuel Jordan
Andrei,完成了...提前致谢。从“在执行Andrei的建议之后”开始有新内容可用。 - Manuel Jordan
1
checkStockAvailability 中你做了什么?我没有看到像 recordInvoice 中那样的数据库查询:执行准备好的 SQL 语句 [INSERT INTO invoiceheader(id, number, date, total) VALUES(?, ?, ?, ?)]。除此之外,日志非常清晰,表明使用了正确的设置启动了一个事务:requires_new、timeout 0 等等。 - Andrei Stefan
1
如果数据库没有活动,那么就没有数据库级事务 :-). 在Java代码中所做的反映在数据库级别上。例如,如果您打开MySQL控制台并在表中插入某些内容,则最终需要提交才能在DB中看到结果 ;-). 这就是事务。 - Andrei Stefan
1
我查看了Hibernate事务的源代码,似乎只有严格大于0的值才会被考虑。请参见此处。尝试一下:将Hibernate的超时设置为1(即一秒钟)。在您的checkStockAvailability方法中,做如下操作:Thread.currentThread.sleep(1500); 如果这引发了预期的错误,则意味着Hibernate不考虑0秒超时,只考虑严格正值。 - Andrei Stefan
显示剩余7条评论
1个回答

1
查看第一批日志(与recordInvoicecheckStockAvailability的超时问题有关),这些确实表明事务行为被正确应用:在Java代码级别,事务被启动和提交。日志的唯一区别在于使用recordInvoice时实际上会执行一个查询来访问数据库,而使用checkStockAvailability时则没有。

可能的答案是,如果没有与数据库的交互,则没有数据库级事务。您在Java代码中所做的反映在数据库级别上。例如,如果您在MySQL控制台打开并插入某些内容到表中,则需要提交才能在数据库中查看结果。

关于您的第二个问题,其中一个测试使用JdbcTemplate,而另一个测试使用Hibernate(使用HibernateTransactionManager),查看Hibernate事务源代码,似乎只考虑严格大于0的值。因此,在事务方法checkStockAvailability中设置超时时间为1秒并添加Thread.sleep(1500)的简单测试可以揭示超时时间为0秒的结果被简单忽略,从而解释了您测试的结果。


感谢您宝贵的支持,安德烈。 - Manuel Jordan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接