今天早上高高兴兴上班,居然收到一大堆报警信息,仔细看了一下具体内容,都在提示这个错误
:"Transaction rolled back because it has been marked as rollback-only"
我一看就觉得奇怪了,为什么会有rollback呢,出现问题的地方,就是一个get查询,而且已经标记为readonly=true了。
下面是项目的事务配置:
没毛病啊,根据事务的传播性默认为REQUIRED,就是“没有则新建一个事务,存在则加入当前事务”。但是一个只读的事务,为啥会有回滚呢?
上网查了一下,返现很多有人都有遇到类似的问题。
原因:
如果getApply()的方法里面调用了一个load()的方法,同时getApply()捕捉了load()方法的异常而没有抛出,则就会报这个错误“”,如果继续往外抛出这个错误就没有问题了。
这是因为事务默认属性配置都为PROPAGATION_REQUIRED,
所以两方法使用的是同一事务,如果load方法出现异常,则org.springframework.transaction.interceptor.
TransactionInterceptor的invoke处理后则会抛出异常.执行completeTransactionAfterThrowing(txInfo, ex);
事务抛出的源码如下:
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
this.logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus);
return;
}
if ((!(shouldCommitOnGlobalRollbackOnly())) && (defStatus.isGlobalRollbackOnly())) {
if (defStatus.isDebug()) {
this.logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus);
if ((status.isNewTransaction()) || (isFailEarlyOnGlobalRollbackOnly())) {
throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only");
}
return;
}
processCommit(defStatus);
}
纠其原理其实很简单,在locad()返回的时候,transaction被设置为rollback-only了,但是getApply()正常消化掉,没有继续向外抛。那么getApply()结束的时候,transaction会执commit操作,但是transaction已经被设置为rollback-only了。
所以会出现这个错误。
调整好问题,找解决方案,问题就出现在propagation="REQUIRED"这个属性上。
标准文档上这样写:
MANDATORY Support a current transaction, throw an exception if none exists. |
NESTED Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else. |
NEVER Execute non-transactionally, throw an exception if a transaction exists. |
NOT_SUPPORTED Execute non-transactionally, suspend the current transaction if one exists. |
REQUIRED Support a current transaction, create a new one if none exists. |
REQUIRES_NEW Create a new transaction, suspend the current transaction if one exists. |
SUPPORTS Support a current transaction, execute non-transactionally if none exists. |
事务配置参考地址: https://blog.csdn.net/bao19901210/article/details/41724355
怎么办?改成supports:
这个状态用一句话概括就是“有则加入事物,无也不创建事物”。对于只读的方法来说,其实不启用事务,也是没有关系的。
参考博客:
https://blog.csdn.net/caolaosanahnu/article/details/6890107