首页 > 其他分享 >Spring事务失效的原因

Spring事务失效的原因

时间:2024-09-13 09:54:18浏览次数:8  
标签:事务 调用 Spring 代理 用户 失效 方法

问题背景

在业务实现当中,多线程并发操作会带来一些安全问题上的挑战。例如,在秒杀业务中,我们不仅要考虑多线程并发执行时对库存的考虑,还要考虑每个用户的请求是否由一个线程发出,当一个用户的请求由多个线程发出时,可能是脚本代刷的情况,这同样会导致业务出现异常。

方法级别的锁

假设我们的秒杀实现方法是:

	public boolean yourServiceMethod(Long someId) {}

考虑到并发问题,我们选择对方法加锁,

	@Transactional
	public synchronized boolean yourServiceMethod(Long someId) {}

但是这样添加锁,锁的粒度太粗了,在使用锁过程中,控制锁粒度 是一个非常重要的事情,因为如果锁的粒度太大,会导致每个线程进来都会锁住,所以我们需要去控制锁的粒度。这样的加锁方式仍然没法满足防止同一用户的多个线程的请求。

理想的锁粒度

应该是细化到用户级别,而不是整个对象实例。比如在秒杀场景中,我们希望同一个用户的请求被串行化(一个用户不能同时发起多个秒杀请求),但允许不同用户同时进行秒杀。

用户级别的锁

锁的粒度应该根据业务需求进行调整,比如通过 用户ID 进行加锁。可以通过 synchronized(userId) 或者 synchronized(userId.toString().intern()) 来锁定不同用户的请求,保证相同用户在一个时间只能有一个秒杀请求被处理,但允许不同用户并行秒杀。

事务失效

解决了实现用户级别的锁的问题,此时还是存在着问题。即:如果在方法内部加锁,可能会导致当前事务还没有提交,但是锁已经释放也会导致问题。所以选择将当前方法包裹起来,确保事务不会出现问题,同时也保证了锁的粒度:

		// 获取用户ID
        Long userId = user.getId();
        synchronized (userId.toString().intern()) {
            return this.yourServiceMethod(someId);
        }

但是以上的方法仍有问题,因为我们调用的方法其实是this调用的,事务要想生效需要使用代理。
Spring 通过 AOP(面向切面编程) 实现事务管理,具体是通过代理对象来增强目标对象的方法,使其具备事务管理的功能。在代码中,@Transactional 注解被用来标识事务,Spring 会为该方法创建代理,代理对象负责开启、提交或回滚事务。(Spring默认使用JDK动态代理)

        Long userId = user.getId();
        synchronized (userId.toString().intern()) {
            // 获取代理对象(事务)
            Service proxy = (Service) AopContext.currentProxy();
            return proxy.yourServiceMethod(someId);
        }

通过代理进行外部调用,便可以解决事务失效问题。
外部调用 vs. 内部调用:如果是外部调用(从类外部调用目标方法),代理对象会接收到方法调用,并正确处理事务。然而,当类内部的方法调用类内另一个带有 @Transactional 注解的方法(即自调用)时,调用是直接通过 this 对象进行的,绕过了代理对象,导致事务拦截器无法介入处理事务逻辑。

Spring事务失效原因
  • 自调用导致事务失效:Spring的事务管理是通过AOP代理实现的。如果一个类中的方法直接调用另一个标注了@Transactional的方法(自调用),事务不会生效。因为事务代理是在外部调用时才生效,内部调用绕过了代理。
  • 方法不是public
  • 异常处理不当
  • 事务传播行为不当
  • AOP代理类型不匹配:Spring默认使用JDK动态代理处理事务,如果事务类没有实现接口且没有强制使用CGLIB代理,可能会导致事务失效。
  • 数据库不支持事务:某些数据库引擎(如MySQL的MyISAM)不支持事务管理。如果使用了不支持事务的数据库引擎,事务自然不会生效。
  • 多线程环境:Spring的事务管理是基于线程绑定的(ThreadLocal)。如果在多线程环境中使用事务,可能会导致事务失效,因为事务状态在不同线程间无法共享。

标签:事务,调用,Spring,代理,用户,失效,方法
From: https://blog.csdn.net/qq_52127701/article/details/142098627

相关文章

  • 数据库———事务及bug的解决
    一:事务1:场景引入张三在银行账户中存有1000元,李四存有500元,这时张三要给李四支付500元,执行sql语句①:updateaccountsetbalance=balance-500wherename='张三';②:updateaccountsetbalance=balance+500wherename='李四';想象一下,如果在sql语句①执行完......
  • 【含文档】基于Springboot+Vue的同城上门喂遛宠物系统的设计与实现(含源码数据库)
    1.开发环境开发系统:Windows10/11架构模式:MVC/前后端分离JDK版本:JavaJDK1.8开发工具:IDEA数据库版本:mysql5.7或8.0数据库可视化工具:navicat服务器:SpringBoot自带apachetomcat主要技术:Java,Springboot,mybatis,mysql,vue2.视频演示地址3.功能系统中......
  • 【含文档】基于Springboot+Vue的大学生计算机基础网络教学系统管理(含源码数据库)
    1.开发环境开发系统:Windows10/11架构模式:MVC/前后端分离JDK版本:JavaJDK1.8开发工具:IDEA数据库版本:mysql5.7或8.0数据库可视化工具:navicat服务器:SpringBoot自带apachetomcat主要技术:Java,Springboot,mybatis,mysql,vue2.视频演示地址3.功能这个系......
  • 【开题报告】基于Springboot+vue基于Web的游戏道具交易平台系统(程序+源码+论文) 计算
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着网络游戏的蓬勃发展,游戏内经济体系日益完善,游戏道具作为虚拟商品已成为玩家间交易的重要组成部分。传统游戏内交易方式受限于平台规则、信任机制......
  • 【开题报告】基于Springboot+vue平安苑小区物业管理系统(程序+源码+论文) 计算机毕业设
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着城市化进程的加速,住宅小区作为城市生活的基本单元,其管理与服务水平直接关系到居民的生活质量与社会和谐。平安苑小区作为现代化社区的代表,其物业......
  • springboot+vue智能充电桩【程序+论文+开题】计算机毕业设计
    系统程序文件列表开题报告内容研究背景随着新能源汽车产业的迅猛发展,电动汽车作为绿色出行的重要载体,其普及率日益提升。然而,电动汽车的广泛应用面临着一个关键挑战——充电基础设施的不足与不便。传统充电桩存在分布不均、使用效率低下、用户体验不佳等问题,难以满足日益增......
  • 十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明)
    十,SpringBoot的内容协商的详细剖析(附+Debug调试说明)文章目录十,SpringBoot的内容协商的详细剖析(附+Debug调试说明)1.基本介绍2.准备工作3.内容协商的本质4.内容协商:注意事项和使用细节5.总结:6.最后:1.基本介绍根据客户端接收能力不同,SpringBoot返回不......
  • springcloud间通信的方式
    在SpringCloud中,主要有以下几种通信方式:一、基于HTTP的RESTfulAPI工作原理:这是一种常见的通信方式,各个微服务通过发送HTTP请求来相互调用。服务提供者暴露RESTfulAPI接口,服务消费者通过HTTP客户端(如RestTemplate、Feign等)发送请求。例如,一个订单服务需要......
  • 【Spring】搭建SpringBoot + OAuth2认证授权服务
    文章目录一、环境准备二、创建SpringBoot项目1.使用SpringInitializr2.使用IDE导入项目三、配置数据源四、添加用户实体和存储五、配置SpringSecurity六、配置OAuth2七、创建控制器八、创建前端页面九、运行和测试十、总结本文将详细介绍如何使用最新版本的Spr......
  • 基于springboot的药店管理系统
    ......