我对@Transactional 超时属性的行为感到困惑
我有以下顺序
Main ->
UserExecutionServiceImpl.executeRecordInvoice ->
ProcessInvoiceServiceImpl.recordInvoice ->
WarehouseServiceImpl.checkStockAvailability
要强制回滚异常超时设置为0。
如果 executeRecordInvoice 有@Transactional(timeout=0)
,则抛出异常并停止所有异常。它有意义
如果 executeRecordInvoice 有@Transactional
且 recordInvoice 有@Transactional(timeout=0)
,则不会抛出异常。实际上,超时值已被忽略。
我可以假设因为事务真的以 executeRecordInvoice 开头,而且因为两种方法都默认为Propagation.Required
,这意味着,第二种( recordInvoice )是在第一个( executeRecordInvoice )内考虑已经存在的正在运行的事务
更重要的是,我做了两个简单的实验:
如果 executeRecordInvoice 有@Transactional
而 recordInvoice 有@Transactional(propagation.Propagation.REQUIRES_NEW, timeout=0)
,则会抛出异常。现在可行,因为新交易始于 recordInvoice ,因此会考虑超时。
直接从主要课程调用ProcessInvoiceServiceImpl.recordInvoice
,@Transactional(propagation.Propagation.REQUIRED, timeout=0)
或@Transactional(propagation.Propagation.REQUIRES_NEW, timeout=0)
,再次超时。
直到这里,我很好,所有人都有道理。但是对于 WarehouseServiceImpl.checkStockAvailability 应用1和2,它不起作用:
如果 executeRecordInvoice 且 recordInvoice 有@Transactional
(因此默认情况下均为Propagation.REQUIRED)且 checkStockAvailability 有{ {1}}。例外情况是不抛出!
直接从主要课程@Transactional(propagation.Propagation.REQUIRES_NEW, timeout=0)
,WarehouseServiceImpl.checkStockAvailability
或@Transactional(propagation.Propagation.REQUIRED, timeout=0)
,再次超时 > 考虑。
班级宣言
@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当然存在......
答案 0 :(得分:1)
查看您的第一个日志(与recordInvoice
与checkStockAvailability
的超时问题相关),这些确实表明正确应用了事务行为:在Java代码级别事务处理已启动并提交。日志的唯一区别在于,recordInvoice
对数据库执行了实际查询,而checkStockAvailability
没有这样的事情。
可能的答案是,如果数据库没有活动,则没有数据库级事务。您在java代码中拥有的内容反映在db级别。例如,如果您打开MySQL控制台并在表中插入内容,最后您需要提交以在DB中查看结果。
与您的第二个问题相关,您在一个测试中使用JdbcTemplate
而另一个使用Hibernate(使用HibernateTransactionManager
),查看source code for the Hibernate transaction似乎只有值严格更高考虑超过0。因此,一个简单的测试涉及将超时设置为一秒,而在事务方法checkStockAvailability
中可以添加Thread.sleep(1500)
,这可以揭示超时的0秒值被忽略,解释测试结果。