当前位置:网站首页>嵌套事务 UnexpectedRollbackException 分析与事务传播策略
嵌套事务 UnexpectedRollbackException 分析与事务传播策略
2022-07-25 11:22:00 【JackLi0812】
UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
1. 问题描述与重现
jfoa提供了Audit的功能, 目标方法(比如添加用户)存在事务管理,
在 Audit 中需要去查询用户(事务管理), 最后在目标方法执行后执行 Audit 记录的插入(事务管理).
即添加用户(事务)中查询用户(事务)就会抛出异常:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
字面意思是:
出现了不可预知的回滚异常,因为事务已经被标志位只能回滚,所以事务回滚了.下面来重现和描述一下这个问题.
@Around("audit()")
public Object recordLog(ProceedingJoinPoint pjp) throws Throwable {
Log log = null;
Customer principal = null;
try {
// note1: 这里获取当前登录的用户, 注意这个方法可以抛出异常
// 1) getCurrentCustomer 在事务管理中
// 2) catch 了方法调用并没有继续抛出异常
principal = customerService.getCurrentCustomer();
} catch (Exception ignore) {
LOGGER.debug("Get principal error!", ignore);
}
// ... 省略一些中间代码
Object result;
try {
// note3: 具体的目标方法
result = pjp.proceed();
}
catch(Throwable throwable) {
if(log != null) {
log.setMessage("Execute Failed: " + throwable.getMessage());
}
throw throwable;
}
finally {
// ...
}
return result;
}
// note2: 目标方法有事务管理
@Audit(ResourceEnum.Customer)
@Transactional
@Override
public Integer insertCustomer(@AuditObject("getName()") Customer user) {
if(isValid(user)) {
user.setPassword(
SecurityUtil.generatorPassword(user.getAccount(), user.getPassword()));
return customerDao.insert(user);
}
return null;
}
注意上方的
note1和note2, 在这种情况下就会出现本文的异常.
2. 原理剖析
因为 spring 的
@Transactional注解默认的事务传播策略为Propagation.REQUIRED,
PROPAGATION_REQUIRED的意思是,当前有事务,则使用当前事务,当前无事务则创建事务。因此, 当
目标方法被调用时, 由于目标方法存在事务, 当目标方法被调用时会开启事务,
当执行到note1时,getCurrentCustomer方法也
存在事务, 根据事务传播策略, spring 就会使用目标方法的事务,
但是getCurrentCustomer有 try-catch 处理, 并且catch没有继续抛出事务,
因此当getCurrentCustomer抛出异常时, spring 要执行 rollback 操作, 但是 catch
没有继续抛出异常, 还会继续调用到note3处继续执行, 当目标方法被调用完成后
由于是正常调用完毕, 因此又需要执行 commit, 所以就会引发该异常.
2.0 事务传播策略简介
spring 定义了如下传播策略:
public enum Propagation {
/** * 当前有事务,则使用当前事务,当前无事务则创建事务 */
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
/** * 支持当前事务,如果不存在,以非事务方式执行。 * 注:对于事务同步的事务管理器,与根本没有事务略有不同, * 因为它定义了同步将应用的事务范围。 * 结果,相同的资源(JDBC连接、Hibernate会话等) * 将为整个指定范围共享。注意,这取决于 * 事务管理器的实际同步配置。 */
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
/** * 如果当前与事务则使用当前事务, 如果当前没事务则抛出异常. */
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
/** * 无论当前是否有事务都创建一个新的事务. * 如果当前有事务则挂起当前事务. */
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
/** * 以非事务方式运行, 如果当前有事务, 则挂起当前事务 */
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
/** * 以非事务方式运行, 如果当前有事务, 则抛出异常 */
NEVER(TransactionDefinition.PROPAGATION_NEVER),
/** * 如果当前事务存在,则在嵌套事务中执行,否则行为类似{@code REQUIRED}. * 注意: 嵌套事务的实际创建只适用于特定的事务管理器。 * 这只适用于JDBC DataSourceTransactionManager。 * 一些JTA提供程序可能也支持嵌套事务。 */
NESTED(TransactionDefinition.PROPAGATION_NESTED);
2.1 默认传播策略
spring 的
@Transactional注解默认的事务传播策略为Propagation.REQUIRED
public @interface Transactional {
// ...
/** * The transaction propagation type. * <p>Defaults to {@link Propagation#REQUIRED}. * @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior() */
Propagation propagation() default Propagation.REQUIRED;
2.2 问题总结
当 methodA 调用 methodB, 并且两个方都有事务(事务嵌套),
且传播策略都为Propagation.REQUIRED时, 就会导致两个方法
共用一个事务,methodB将事务标志为回滚,methodA中commit这个事务,
然后就会出现事务已经被标志回滚(methodB标志的)的异常信息.
3. 解决方法
知道了问题出现的原因, 自然就知道了解决办法, 但是不同的业务场景解决方式可能不同,
大家需要结合自己的业务场景选择合适的解决方案
3.1 修改 try-catch
对内部方法 methodB 不要进行 try-catch 或者 catch 继续抛出异常.
3.2 修改事务传播策略
- 如果修改外部事务 methodA 的事务传播策略, 则 methodA 只能取消事务(一般不可用).
- 修改内部 methodB 的事务传播策略, 一般可改为
REQUIRES_NEW,NOT_SUPPORTED,NESTED.NOT_SUPPORTED都把内部事务转换为非事务运行.REQUIRES_NEW会创建一个新事务运行.NESTED在嵌套事务运行.
比如帅帅我这里的业务场景, 首先是需要事务管理, 因此我这里可以使用
REQUIRES_NEW,NESTED,
其次, audit 记录以及,getCurrentCustomer无论何时都不应该影响核心业务逻辑的运行,因此,
最终我选择修改事务传播策略为REQUIRES_NEW来解决这个问题. 如果您的嵌套事务和主事务有关联关系,
那么您就应该选择NESTED.
最后, 还需要注意一点: 同一个类中,事务嵌套以最外层的方法为准,嵌套的事务失效;不同类中嵌套的事务才会生效;

边栏推荐
- How to solve the problem of the error reported by the Flink SQL client when connecting to MySQL?
- 【GCN-RS】Region or Global? A Principle for Negative Sampling in Graph-based Recommendation (TKDE‘22)
- PHP uploads the FTP path file to the curl Base64 image on the Internet server
- Meta-learning(元学习与少样本学习)
- Go 垃圾回收器指南
- Brpc source code analysis (VII) -- worker bthread scheduling based on parkinglot
- Qin long, a technical expert of Alibaba cloud: a prerequisite for reliability assurance - how to carry out chaos engineering on the cloud
- brpc源码解析(四)—— Bthread机制
- 【AI4Code最终章】AlphaCode:《Competition-Level Code Generation with AlphaCode》(DeepMind)
- 那些离开网易的年轻人
猜你喜欢

剑指 Offer 22. 链表中倒数第k个节点

【多模态】《HiT: Hierarchical Transformer with Momentum Contrast for Video-Text Retrieval》ICCV 2021

【AI4Code最终章】AlphaCode:《Competition-Level Code Generation with AlphaCode》(DeepMind)

Brpc source code analysis (V) -- detailed explanation of basic resource pool

brpc源码解析(八)—— 基础类EventDispatcher详解

Solutions to the failure of winddowns planning task execution bat to execute PHP files

Learning to pre train graph neural networks

【多模态】《TransRec: Learning Transferable Recommendation from Mixture-of-Modality Feedback》 Arxiv‘22

从云原生到智能化,深度解读行业首个「视频直播技术最佳实践图谱」

30 sets of Chinese style ppt/ creative ppt templates
随机推荐
R语言ggplot2可视化:可视化散点图并为散点图中的部分数据点添加文本标签、使用ggrepel包的geom_text_repel函数避免数据点之间的标签互相重叠(为数据点标签添加线段、指定线段的角度
Hardware connection server TCP communication protocol gateway
【多模态】《TransRec: Learning Transferable Recommendation from Mixture-of-Modality Feedback》 Arxiv‘22
R语言ggpubr包ggarrange函数将多幅图像组合起来、annotate_figure函数为组合图像添加注释、注解、标注信息、fig.lab参数添加图像标签、fig.lab.face参数指定样式
【微服务~Sentinel】Sentinel降级、限流、熔断
What is the difference between session and cookie?? Xiaobai came to tell you
Brpc source code analysis (VI) -- detailed explanation of basic socket
Eureka注册中心开启密码认证-记录
brpc源码解析(二)—— brpc收到请求的处理过程
Median (二分答案 + 二分查找)
【AI4Code】《CoSQA: 20,000+ Web Queries for Code Search and Question Answering》 ACL 2021
GPT plus money (OpenAI CLIP,DALL-E)
容错机制记录
NLP knowledge - pytorch, back propagation, some small pieces of notes for predictive tasks
异构图神经网络用于推荐系统问题(ACKRec,HFGN)
硬件连接服务器 tcp通讯协议 gateway
Eureka使用记录
Brpc source code analysis (V) -- detailed explanation of basic resource pool
基于TCP/IP在同一局域网下的数据传输
Application and innovation of low code technology in logistics management