Question, I did add the annotation
@Transactional
to the service as usual. Why do I still find data inconsistencies when querying the database? I think it must be that the transaction did not work and an exception occurred. The data is not rolled back. So I tested the relevant code, and found that I had stepped into two pits. It was indeed the data inconsistency caused by the transaction not being rolled back. Let’s summarize the lessons learned:
Programmatic transaction management
Rarely used in actual applications
Manually manage transactions by using TransactionTemplate
@Servicepublic class RabbitServiceImpl implements RabbitService { @Autowiredprivate RabbitDao rabbitDao; @Autowiredprivate TortoiseDao tortoiseDao; @Overridepublic Rabbit methodA(String name){return methodB(name); } @Transactional(propagation = Propagation.REQUIRED)public boolean methodB(String name){ rabbitDao.insertRabbit(name); tortoiseDao.insertTortoise(name);return true; } }
public class RabbitServiceImplTest { @Autowiredprivate RabbitService rabbitService;// 事务未开启 @Testpublic void testA(){ rabbitService.methodA("rabbit"); }// 事务开启 @Testpublic void testB(){ rabbitService.methodB("rabbit"); } }
@Transactional(propagation = Propagation.REQUIRED)public boolean methodB(String name) throws BizException {try { rabbitDao.insertRabbit(name); tortoiseDao.insertTortoise(name); } catch (Exception e) {throw new BizException(ReturnCode.EXCEPTION.code, ReturnCode.EXCEPTION.msg); }return true; }
public class BizException extends Exception {// 自定义异常}
runtime, unchecked exceptions as rollback; that is to say, throwing in the transaction The exception that occurs is RuntimeException or its subclass, so that the transaction will be rolled back (Error will also cause the transaction to be rolled back by default). With the default configuration, all checked exceptions will not cause transaction rollback.
Note: Unchecked Exception includes Error and RuntimeException. All subclasses of RuntimeException also belong to this category. The other type is checked Exception.
<advice> <attributes> <method></method> <method></method> </attributes> </advice>
@Transactional(rollbackForClassName={"Exception"}) 或者 @Transactional(rollbackFor={Exception.class})
在你遇到异常不想回滚事务的时候,同样的你也可指定不回滚的规则,下面的一个例子告诉你,即使遇到未处理的 InstrumentNotFoundException
异常时,Spring FrameWork 的事务框架同样会提交事务,而不回滚。
<advice> <attributes> <method></method> <method></method> </attributes> </advice>
与其有同样作用的注解形式如下:
@Transactional(noRollbackForClassName={"InstrumentNotFoundException"}) 或者 @Transactional(noRollbackFor={InstrumentNotFoundException.class})
还有更灵活的回滚规则配置方法,同时指定什么异常回滚,什么异常不回滚。当Spring FrameWork 的事务框架捕获到一个异常的时候,会去匹配配置的回滚规则来决定是否标记回滚事务,使用匹配度最强的规则结果。因此,下面的配置例子表达的意思是,除了异常 InstrumentNotFoundException
之外的任何异常都会导致事务回滚。
<advice> <attributes> <method></method> </attributes> </advice>
你也可以通过编程式的方式回滚一个事务,尽管方法非常简单,但是也有非常强的代码侵入性,使你的业务代码和Spring FrameWork 的事务框架代码紧密的绑定在一起,示例代码如下:
public void resolvePosition() { try { // some business logic... } catch (NoProductInStockException ex) { // trigger rollback programmatically TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }
如果可能的话,强烈推荐您使用声明式事务方式回滚事务,对于编程式事务,如果你强烈需要它,也是可以使用的,but its usage flies in the face of achieving a clean POJO-based architecture.(没懂...)
看完官方文档这节内容找到了问题的答案,原来是因为我们自定义的异常不是 RuntimeException
。我的解决办法是,在注解@Transactional
中添加 rollbackFor={BizException.class}
。可能你会问我为什么不将自定义异常修改为继承RuntimeException,因为我需要BizException是一个checked 异常。
The above is the detailed content of Spring transaction management operation method. For more information, please follow other related articles on the PHP Chinese website!