当前位置: 首页 > news >正文

Spring事务粒度优化与传播机制

在Spring事务中,我们通常会为了控制事务粒度,会把它进行拆分,为了避免大事务执行太久,占用资源太多,导致资源利用率低的问题。

我们曾经就遇到老系统因为大事务,把服务打死了。

问题出在一个大事务中有一个Excel文件解析的操作,有用户上传的某个文件,有1百多万个空行数据。

因为,这个事务一致不能结束,直接导致系统崩溃。

但是要拆分事务,是一个麻烦的事情,要考虑事务传播机制。

无事务

我相信很多朋友都遇到过事务不生效的情况,最常见的就是下面这种情况:

public class ServiceA
{public void methodA(){methodB();}@Transactionalpublic void methodB(){}
}

我相信有朋友已经开始笑了。

不要笑,相信很多朋友本能会犯这个错误,因为这种方式最简单。

上面的示例,事务是不会生效的,因为methodB直接被调用,是因为没有通过代理执行。

问题很简单,但是如何快速简单的解决问题呢?

有事务不回滚

有对事务传播机制比较熟悉的朋友,可能要提出下面的方案了:

public class ServiceA
{@Transactional(propagation = Propagation.SUPPORTS)public void methodA(){methodB();}@Transactionalpublic void methodB(){}
}

既然,没有事务,我加上事务不加完了,SUPPORTS机制,没有事务就不创建,有事务就在事务中执行,
然后,methodB默认事务传播机制REQUIRED,没有就会创建事务。

所以,methodA没有事务,methodB直接创建事务执行,真是天才的想法啊。

问题是,实际情况真是这样吗?

比较遗憾,不是。

会有事务吗?会methodA会生成事务。

methodB会生成新的事务吗?不会,因为methodA已经有事务了。

会回滚吗?不会!有事务,但是不会回滚。

和不加@Transactional(propagation = Propagation.SUPPORTS)相比,只是会创建事务了。

为什么会出现这样的情况呢?

开的的时候,我以为是SUPPORTS没有回滚点的造成。

但是,我发现还是存在其他没有回滚点的事务传播机制,并且能够回滚

可以添加下面的代码打印看一下:

System.out.println(TransactionAspectSupport.currentTransactionStatus().hasSavepoint());

还有什么办法吗?

换个姿势调用

很多时候,我们没有得到正确的结果,可能是姿势不对,我们换个姿势试一试。

既然,直接调用不行,那我们通过ApplicationContext来调用,是否就可以触发事务了呢?

@Component
public class ApplicationContextHolder implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public ApplicationContext getApplicationContext(){return this.applicationContext;}public <T> T  getService(Class<T> clazz){return applicationContext.getBean(clazz);}
}
public class ServiceA
{@Resourceprivate ApplicationContextHolder applicationContextHolder;public void methodA(){ServiceA service = applicationContextHolder.getService(this.getClass());service.methodB();}@Transactionalpublic void methodB(){}
}

答案是:不行,因为根本没有创建事务

多种姿势结合

public class ServiceA
{@Resourceprivate ApplicationContextHolder applicationContextHolder;@Transactional(propagation = Propagation.SUPPORTS)public void methodA(){ServiceA service = applicationContextHolder.getService(this.getClass());service.methodB();}@Transactionalpublic void methodB(){}
}

这样可以吗?

答案是:可以

事务是methodA的事务,并且也回滚了。

这的确解决了我们的问题,但是也违背了我们的初衷:将事务粒度变小。

因为,绕了一大圈,发现还是相当于methodA上的事务了。

那有没有什么更靠谱的解决方案呢?

大概可以试一试:NESTED和REQUIRES_NEW事务吧

public class ServiceA
{@Transactional(readOnly = true)public void methodA(){ServiceA service = applicationContextHolder.getService(this.getClass());service.methodB();}@Transactional(propagation = Propagation.NESTED)// @Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB(){}
}

可以回滚,但是:

  1. NESTED、REQUIRES_NEW都没有回滚点
  2. NESTED、REQUIRES_NEW都使用的是methodA的事务。

感觉和直接调用没有太多的区别

@Service
public class ServiceA
{@Resourceprivate ServiceB serviceB;public void methodA(){serviceB.methodB();}
}@Service
public class ServiceB
{    //    @Transactional(propagation = Propagation.NESTED)@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB(){}
}

上面的方式,也可以回滚:

  1. 使用NESTED有回滚点,使用methodA的事务
  2. 使用REQUIRES_NEW,会创建新事务

事务传播机制

http://www.lryc.cn/news/242243.html

相关文章:

  • MySQL 基于成本的优化
  • 【maven】【IDEA】idea中使用maven编译项目,报错java: 错误: 找不到符号 【2】
  • AIGC,ChatGPT AI绘画 Midjourney 注册流程详细步骤
  • 万字解析设计模式之模板方法与解释器模式
  • apipost接口200状态码,浏览器控制台500状态码
  • Instant Web API .Net Core Crack
  • vue项目使用easyplayer播放m3u8直播推流
  • Python报错:AttributeError(类属性、实例属性)
  • vue+springboot读取git的markdown文件并展示
  • 多功能PHP图床源码:Lsky Pro开源版v2.1 – 最新兰空图床
  • Hive内置表生成函数
  • 电源控制系统架构(PCSA)之电源控制框架概览
  • Sentinel 监控数据持久化(mysql)
  • 基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码
  • canvas高级动画001:文字瀑布流
  • 抽象类, 接口, Object类 ---java
  • SOAP 协议和 HTTP 协议:深入解读与对比
  • Unity发布IOS后,使用xcode打包报错:MapFileParser.sh:Permissiondenied
  • 2021年12月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试
  • mac上Homebrew的安装与使用
  • YOLOv5 分类模型 预处理 OpenCV实现
  • 在arm 64 环境下使用halcon算法
  • H5(uniapp)中使用echarts
  • QLineEdit设置掩码Ip
  • 开源语音大语言模型来了!阿里基于Qwen-Chat提出Qwen-Audio!
  • 缓存雪崩、击穿、穿透及解决方案_保证缓存和数据库一致性
  • 仿 美图 / 饿了么,店铺详情页功能
  • Redis Cluster主从模式详解
  • Linux技能篇-非交互式修改密码
  • 记一次docker服务启动失败解决过程