@Transactional 事务加了 锁 为什么还有并发问题?

2023-05-16

一、原因分析

Spring 中通过在方法上添加注解 @Transactional 可以很好的处理事务问题。Spring对此的处理原理是对 加了 @Transactional 注解的方法 添加 AOP切面来时先事务管理的。
synchronized 最大范围也就是方法级别的。 事务和synchronized 关系如下所示
在这里插入图片描述
由上图可以看出,当线程1 释放了锁,还未提交事务之前,线程2 已经获取锁并提前提交了事务,从而导致了并发的问题。

二、解决方法

1、方法一 增强事务隔离级别

可以把事务的隔离级别设置为 SERIALIZABLE 不允许事务并发执行,而必须串行化执行,最安全,不可能出现更新、脏读、不可重复读、幻读,但是效率最低。

 @Transactional(isolation = Isolation.SERIALIZABLE)
    public synchronized void update(Long id, Long seq){
        Test1Entity entity = test1Mapper.selectById(id);
        test1Mapper.updateById(new Test1Entity(id, seq + entity.getSeq()));
    }

2、方法二 提升加锁位置

如果业务逻辑非常简单,对高并发行要求不高的话,可以把 锁操作添加到 控制层,如下所示:

 // Controller
   @PutMapping("/update/{id}/{seq}")
    public Test1Entity update(@PathVariable("id") Long id,
                             @PathVariable("seq") Long seq){
        // 添加锁操作。 
        synchronized (Class.class){ // 此处为了示例,要根据业务合理加锁
            testService.update(id, seq);
        }
        return new Test1Entity(id, seq);
    }

 // Service
@Service
public class TestServiceImpl {
    @Resource
    private Test1Mapper test1Mapper;
    
    @Transactional
    public void update(Long id, Long seq){
        Test1Entity entity = test1Mapper.selectById(id);
        test1Mapper.updateById(new Test1Entity(id, seq + entity.getSeq()));
    }
}

3、方法三 抽离事务代码

方法一和方法二的效率都比较低,另一种方式可以把,可以把需要 把需要并发控制的业务,单独抽离出来,进行事务控制操作。如下所示:


public void complex(Long id, Long seq){
        // 其他业务处理
        lock.lock();
        try {
            service.update(id, seq);
        } finally {
           lock.unlock();
        }
        // 其他业务处理
    }

    @Transactional
    public void update(Long id, Long seq){
        Test1Entity entity = test1Mapper.selectById(id);
        test1Mapper.updateById(new Test1Entity(id, seq + entity.getSeq()));
    }

4、方法四 手动开启事务

方法三中可能会增加一个类的编写,也可以在同一个方法中通过手动开启事务的方式实现。如下所示:


@Service
public class TestServiceImpl {

    @Resource
    private Test1Mapper test1Mapper;

    private static final Lock lock = new ReentrantLock();
    
    @Resource
    private  DataSourceTransactionManager transactionManager;
    @Resource
    TransactionDefinition transactionDefinition;

    public void update(Long id, Long seq){
        // 其他业务处理
        lock.lock();
        // 开启事务
        TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);;
        try {
            Test1Entity entity = test1Mapper.selectById(id);
            test1Mapper.updateById(new Test1Entity(id, seq + entity.getSeq()));

            // 提交事务
            transactionManager.commit(transaction);
        }catch (Exception e){
            // 回滚事务
            transactionManager.rollback(transaction);
        }finally {
           lock.unlock();
        }
        // 其他业务处理
    }

}

这个手动开启事务,需要每个方法都需要实现,这个也是比较繁琐,这种方式可以抽象出一个公共类,统一来实现事务的处理。 可以自己脑补

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

@Transactional 事务加了 锁 为什么还有并发问题? 的相关文章

  • @Transactional 注解失效情况及解决办法

    一 64 Transactional 注解在了非 public 方法上 如下所示 64 Transactional修饰在了非public方法上 span class token annotation punctuation 64 Servi
  • @Transactional 事务加了 锁 为什么还有并发问题?

    一 原因分析 Spring 中通过在方法上添加注解 64 Transactional 可以很好的处理事务问题 Spring对此的处理原理是对 加了 64 Transactional 注解的方法 添加 AOP切面来时先事务管理的 而 sync
  • jeecgboot @Transactional捕获异常并拿到返回值

    64 Transactional 和 64 RestControllerAdvice 并不冲突 回滚的同时拦截异常返回需要的值给前端 64 Override 64 Transactional rollbackFor 61 Exception
  • @Transactional 详解

    前些天发现了一个巨牛的人工智能学习网站 xff0c 通俗易懂 xff0c 风趣幽默 xff0c 忍不住分享一下给大家 点击跳转到教程 64 Transactional 是声明式事务管理 编程中使用的注解 1 添加位置 1 xff09 接口实
  • @Transactional注解事务失效的七种原因分析

    64 Transactional是一种基于注解管理事务的方式 xff0c spring通过动态代理的方式为目标方法实现事务管理的增强 64 Transactional使用起来方便 xff0c 但也需要注意引起 64 Transactiona
  • 第二篇:Spring Boot整合JPA、事务处理及AOP的使用

    一 Spring Boot整合JPA的具体步骤 注 Spring Boot整合JPA 源码下载 注 springboot学习资料汇总 参考 spring data jpa的使用 参考 Spring Cloud微服务实战 作者 参考 方志朋博
  • 在 Spring 应用程序的事务中使用 Async

    我有一个 Spring 应用程序 它使用以下命令更新 MySQL DB 中的特定实体详细信息 Transactional方法 并且在同一方法中 我尝试使用调用另一个端点 Async这是另一个 Spring 应用程序 它从 MySql DB
  • Spring Hibernate - 无法获取当前线程的事务同步会话

    我为什么要发布这个 经过几个小时的搜索 分析 变得偏执后 我想与您分享我的错误 我确定了问题的原因 什么时候发生的 在应用程序服务器内 在我的例子中嵌入了tomcat 测试没有问题 在两个特定的 Services 上 方法已使用 Trans
  • Spring事务上下文不持久保存数据

    我知道我的问题是一个常见问题 但是我在这里检查了很多问题 检查了Spring文档 我真的不知道我做错了什么 我的问题 我有一个使用 JPA 的 Spring WebFlow 项目 实现 OpenJPA MySQL 数据库 我使用 Sprin
  • 集中回滚-用于使用@transactional

    是否可以告诉Spring回滚异常MyException也RuntimeException使用时在 XML 配置中 transactional 我知道可以在注释中设置回滚 但如果我有很多服务都设置相同的异常 那么这似乎是多余的 我看到人们建议
  • java.lang.IllegalArgumentException:无法设置为 com.sun.proxy.$Proxy

    我正在使用 Spring MVC 开发一个网络应用程序 这是我得到的异常 Exception while loading the app java lang IllegalStateException ContainerBase addCh
  • Spring、事务、Hibernate 过滤器

    我在 Spring 中使用声明式事务 我有一个带有 事务性 注释的服务层 该服务层调用 DAO 我需要在所有 dao 方法中启用 hibernate 过滤器 我不想每次都显式调用 session enablefilter 那么有没有一种方法
  • @Transactional Spring MyBatis 不工作

    我有一个 Spring Web 应用程序 一切都很好 但现在我需要一种方法来进行事务处理 这是我的 applicationContext xml
  • 了解嵌套 Spring @Transactional 的工作原理

    我正在将 EJB 应用程序移植到 Spring 但遇到了一些问题 该应用程序使用 eclipselink 独立运行 这就是我们选择 spring 的原因 在此应用程序中 我需要创建一个订单 为此我首先需要创建一个客户 OrderLines
  • Seam @Transactional 注释不起作用?

    我在接缝组件上使用 Transactional 注释 类似于 Name myComponent AutoCreate public class MyComponent public void something doWork Transac
  • 注入 DAO 的 @Transactional 的 Spring WS 拦截器不起作用

    我们有一个基于 XML 的传统配置 spring ws 应用程序 其中包含端点拦截器 这些端点拦截器已注入 DAO 以从数据库获取配置 这些 DAO 注入了 hibernate sessionFactory 当我们升级到 spring 4
  • Spring @Transactional 未创建所需的事务

    好吧 我终于屈服于同行压力并开始在我的网络应用程序中使用 Spring 所以我试图让交易处理的东西发挥作用 但我似乎无法做到这一点 我的 Spring 配置如下所示
  • 在日志中显示 Spring 事务

    我为 spring 配置了事务支持 有什么方法可以记录事务以确保我正确设置所有内容 在日志中显示是查看正在发生的情况的好方法 in your log4j properties 对于替代记录器或 log4j 的 xml 格式 请查看文档 根据
  • 如何使用事务范围的持久化上下文进行非事务性读取查询?

    我读了 Spring 文档 它说 PersistenceContext 注解有一个可选的属性类型 默认为 PersistenceContextType TRANSACTION 此默认值是您接收共享所需的 实体管理器代理 这是否意味着我必须让
  • Grails 2.3 IntegrationSpec 不能为事务性 false

    我最近升级到 Grails 2 3 并尝试将所有旧测试迁移到 spock 集成测试 但它在清理时失败了 因为我的测试是非事务性的 Grails 文档说测试可以是非事务性的 但我们需要手动处理它 但在这里似乎不太正确 因为我在扩展 Integ

随机推荐

  • NVIDIA Jetson TX2 查看系统相关+运行demo

    1 查看Jetson TX2 L4T版本 xff1a head n 1 etc nv tegra release 2 查看系统版本 xff1a cat etc lsb release 3 查看系统内核 xff1a uname a 4 查看内
  • Docker镜像迁移至新的服务器(全部数据)

    1 找到你想移动的 Docker 容器的 ID 2 提交你的变更 xff0c 并且把容器保存成镜像 xff0c 命名为 newimage docker commit span class token number 3 span a09b25
  • 配置VNC环境在windows主机访问阿里云linux服务器

    配置VNC环境在windows主机访问阿里云linux服务器 虽然作为服务器使用更多的是使用字符终端连接服务器 xff0c 进行操作 xff0c 因为图形界面很消耗性能和资源 xff0c 但有的时候使用图形界面进行操作更为便捷 xff0c
  • pythondataframe输出小结

    在使用dataframe时遇到datafram在列太多的情况下总是自动换行显示的情况 xff0c 导致数据阅读困难 xff0c 效果如下 xff1a coding utf 8 import numpy as np import pandas
  • 聊聊 Redis 为什么构建自己的简单动态字符串 SDS

    我们知道 xff0c Redis 支持字符串 哈希 列表 集合和有序集合五种基本类型 那么我们如何把图片 音频 视频或者压缩文件等二进制数据保存到 Redis 中呢 xff1f 之前在使用 Memcached 缓存这类数据时是把它们转换成
  • 聊聊 Redis 高可用之持久化AOF和RDB分析

    Redis 持久化概述 Redis 是内存数据库 xff0c 数据都是存储在内存中 xff0c 为了避免进程退出导致数据的永久丢失 xff0c 需要定期将 Redis 中的数据以某种形式把内存中的数据保存到磁盘中 xff1b 当 Redis
  • mysqldump: Got error: 1044: Access denied for user XXXX when doing LOCK TABLES

    一 报错信息 在使用mysqldump 执行远程备份数据库的时候报如下错误 xff1a mysqldump Got error span class token number 1044 span Access denied span cla
  • jmap -heap [pid]运行报:Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException(不允许的操作)

    一 运行环境 操作系统 xff1a Ubuntu 5 4 0 6 Java版本 xff1a JDK8 二 执行命令 jmap heap span class token punctuation span pid号 span class to
  • chkconfig: command not found

    问题描述 在 ubuntu1 16 04 10 执行 chkconfig 命令报 chkconfig command not found 说明此服务上没有安装 chkconfig 执行如下命令进行安装 span class token fu
  • Docker 基础篇 之 安装

    一 Docker安装 查看 CentOS 内核版本 Docker 要求 CentOS 系统的内核版本高于3 10 执行如下命令查询 内核版本 span class token function uname span r span class
  • Java 基础 之 Valid 验证

    一 64 Valid 简介 Bean Validation 内置的校验器 校验器说明 64 Null被注解的元素必须为 null 64 NotNull被注解的元素必须不为 null 64 AssertTrue被注解的元素必须为 true 6
  • HttpURLConnection链接详解

    HttpURLConnection链接详解 一 简介 简单来说 xff0c HttpURLConnection 是 Java 提供的发起 HTTP 请求的基础类库 xff0c 提供了 HTTP 请求的基本功能 xff0c 不过封装的比较少
  • Apache HttpClient 详解

    1 简介 HttpClient 是 Apache Jakarta Common 下的子项目 xff0c 用来提供高效的 最新的 功能丰富的支持 HTTP 协议的客户端编程工具包 xff0c 并且它支持 HTTP 协议最新的版本和建议 Htt
  • OKHttp使用详解

    1 简介 OkHttp 是一个默认高效的 HTTP 客户端 xff1a HTTP 2 支持允许对同一主机的所有请求共享一个套接字 连接池减少了请求延迟 xff08 如果 HTTP 2 不可用 xff09 透明 GZIP 缩小了下载大小 响应
  • python二维码生成与扫码

    1 import qrcode img 61 qrcode make 34 hello world 34 img get image show img save 39 hello png 39 2 import qrcode qr 61 q
  • C语言可变参数(从stdarg.h到应用)

    1 什么是可变参数函数 在C语言编程中有时会遇到一些参数可变的函数 xff0c 例如printf scanf xff0c 其函数原型为 xff1a span class token keyword int span span class t
  • OkHttp 缓存实战

    1 简介 在实际业务中可能某些查询数据 xff0c 不经常变化 xff0c 为了节省流量 提高响应速度和增强用户体验等 xff0c 把变化频率小的数据缓存到本地 xff0c 以实现复用 OkHttp 的缓存功能使用起来也比较简单和灵活 xf
  • Feign 详解

    1 Feign 是什么 Feign是一个http请求调用的轻量级框架 xff0c 可以以Java接口注解的方式调用Http请求 Feign通过处理注解 xff0c 将请求模板化 xff0c 当实际调用的时候 xff0c 传入参数 xff0c
  • @Transactional 注解失效情况及解决办法

    一 64 Transactional 注解在了非 public 方法上 如下所示 64 Transactional修饰在了非public方法上 span class token annotation punctuation 64 Servi
  • @Transactional 事务加了 锁 为什么还有并发问题?

    一 原因分析 Spring 中通过在方法上添加注解 64 Transactional 可以很好的处理事务问题 Spring对此的处理原理是对 加了 64 Transactional 注解的方法 添加 AOP切面来时先事务管理的 而 sync