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

@Transactional和synchronized同时使用时的一些问题以及解决

@Transactional和synchronized同时使用并不能保证事务一致性

背景

任何事情都有一个发生背景
有个需求【一个业务里面包含多个事务,而且还需要避免其他线程的影响,所幸的是该服务只需要启动单实例,不然还要考虑分布式的影响】
我的思路就是用@Transactional 和 synchronized来保证事务一致性和多线程影响,结果发现并没有如愿

分析原因

    @Transactionalpublic ResultVo service(){synchronized (LOCK){//doservice}}
关于为什么不是用synchronized 关键字而是使用代码块锁是为了不影响其他方法,关键字默认锁的是当前类对象
一开始我的代码是这样的,乍一看好像没什么问题,但是为什么会出问题呢

排查问题

问题重现 : 一定要重现问题,任何重现不了的问题都不是问题,任何存在的问题都必能重现
由近到远 : 先确认自己的代码没问题,再考虑外部代码(如二方库,三方库)
从内到外 : 程序本质就是IPO,包含输入(input),程序(program)/指令集,输出(output),先确认输入没有问题,再确认代码逻辑
由浅入深 : 从易到难,从上到下,先上层API,http传输等,再底层API,源码,jvm等

说到这里,问题就比较容易分析了

首先我的输入没有问题

其次我逻辑代码也没有问题

接下来就是二方库和三方库了

由于事务用的是spring的事务,是基于aop实现的,ok找到问题了

由于spring的aop,会在@Transactional修饰的方法之前开启事务,之后再加锁,当锁住的代码执行完成后,在提交事务,
因此synchronized代码块执行是在事务之内执行的,可以推断在代码块执行完时,事务还未提交,其他线程进入synchronized代码块后,读取的库存数据不是最新的。

解决问题

在网上看到很多解决方案都在说在外层套一个方法,把锁的级别提高,或则说在controller加锁
这样可能会导致事务不会回滚
spring事务管理中,使用Synchronized修饰事务方法,同步为什么会失效
https://blog.csdn.net/weixin_54401017/article/details/129768305
这里提供一个解决方案,利用线程池,当然业务代码还是要加@Transactional的!!!
private ExecutorService executorService = null;//线程池public ResultVo updateOk(@RequestBody OtcTransferOutManageVo otcTransferOutManageVo){//如果线程池为null或则线程池被关闭了,创建一个单线程化线程池if (executorService == null || executorService.isShutdown()) {executorService = Executors.newSingleThreadExecutor();}if (otcTransferOutManageVo.getId() == null) {return ResultVoBuildUtils.buildResultVo( Constants.FAIL, "参数错误" );}//使用submit执行业务  Future和result.get()是为了保障线程同步,不然变成异步线程是无法捕获异常信息的Future<ResultVo> result = executorService.submit(()->{ResultVo resultVo = otcTransferOutManageService.updateOkStatus(otcTransferOutManageVo);LoggerHepler.writeInfoLog( TransferInController.class, resultVo.getMsg() );return resultVo;});executorService.shutdown();try {return result.get();} catch (Exception e) {LoggerHepler.writeErrorLog( TransferOutManageController.class, ServiceTypeENUM.ASSET_MANAGEMEN, BusinessTypeENUM.TRADE,ExceptionCodeConstants.UPDATE_MYSQL_EXCEPTION, "updateOk error!", e );return ResultVoBuildUtils.buildFaildResultVo();}}
关于这段代码有几点需要说一下

newSingleThreadExecutor()创建单线程化的线程池

通过源码可以看到 :
该方法创建一个单一工作线程的线程池,如果此线程在执行过程中失败了,会有一个新的线程来继续完成未完成的工作
任务会被保证是顺序执行的(串行),并且再任意时间都不会超过一个活跃线程
这里基于的是LinkedBlockingQueue,这是一个线程安全的阻塞队列

shutdown()方法

在调用这个方法后,会在submit的任务执行完成后将线程池变为shutdown状态,拒绝新的任务(线程池不会立刻退出,直到任务完成)
如果已经关闭了,调用此方法也不会有额外的影响
此时不能再往线程池中添加新任务,否则会抛出RejectedExecutionException异常。
  • Future && get()

因为这里需要获取线程执行的返回值,
无论是继承Thread类还是实现Runnable接口都无法获取到线程执行的返回值(默认是异步线程)
所以这里用到的是线程的第三种创建方式,实现callable接口重写call方法,当然重写call方法被我用lambda表达式隐含了
所以get()就是为了获取线程执行的返回值

submit()方法

传入一个Callable 任务,返回执行完成的返回值

相关文章:

@Transactional和synchronized同时使用时的一些问题以及解决

Transactional和synchronized同时使用并不能保证事务一致性背景任何事情都有一个发生背景有个需求【一个业务里面包含多个事务,而且还需要避免其他线程的影响,所幸的是该服务只需要启动单实例,不然还要考虑分布式的影响】我的思路就是用Transactional 和 synchronized来保证事务…...

贪心-根据身高重建队列

假设有打乱顺序的一群人站成一个队列&#xff0c;数组 people 表示队列中一些人的属性&#xff08;不一定按顺序&#xff09;。每个 people[i] [hi, ki] 表示第 i 个人的身高为 hi &#xff0c;前面 正好 有 ki 个身高大于或等于 hi 的人。 请你重新构造并返回输入数组 peopl…...

「解析」牛客网-华为机考企业真题 21-40

又是一年春招时&#xff0c;有幸收到华为自动驾驶算法岗&#xff0c;之前刷题不多&#xff0c;在此汇总下牛客网的真题&#xff0c;主要采用Python编写&#xff0c;个人觉得语言只是实现工具而已&#xff0c;并不是很关键&#xff0c;Python简洁易懂&#xff0c;更加适合算法工…...

JAVA练习92-快乐数

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 3月28日练习内容 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、题目-…...

BPF 之路:技术背景

目录 引言 什么是BPF 历史 组成 执行机制 BPF 和ebpf 的关系 BCC、bpftrace、IO Visor BCC 项目的quick start execsnoop biolatency 动态插桩&#xff1a;kprobes和uprobes 概念 缺点 静态插桩&#xff1a;tracepoint 和USDT 概念 缺点 推荐的方案 初识bpft…...

C++—— set、map、multiset、multimap

目录 关联式容器 概念 键值对 树形关联式容器 set 介绍 定义方式 使用 map 介绍 使用 multiset 介绍 使用 multimap 介绍 使用 相关的OJ题 前K个高频单词 关联式容器 概念 我们之前接触过的一些容器&#xff0c;比如&#xff1a;vector、list、deque、forwa…...

Qlib使用

Qlib https://github.com/microsoft/qlib 将csv文件转化为Qlib的数据格式&#xff1a;https://qlib.readthedocs.io/en/latest/component/data.html#converting-csv-format-into-qlib-format 注意每支股票都要保存成单独一个文档&#xff0c;且文档名字与股票代号一致。 其中f…...

TL-WDR7660 httpProcDataSrv任意代码执行漏洞复现分析

01 漏洞简述 2023年1月31日&#xff0c;CNVD公开了一个由国内安全研究员提交的TL-WDR7660 httpProcDataSrv任意代码执行漏洞&#xff0c;编号为CNVD-2023-05404&#xff0c;同时公开了漏洞利用详情&#xff0c;poc代码链接为https://github.com/fishykz/TP-POC。从poc代码详情…...

基于DDS的SOA测试方案实现

随着以太网技术在车载网络中的应用&#xff0c;各种基于以太网的中间件也相继被应用在车内&#xff0c;如果对车载网络有过相关了解的小伙伴&#xff0c;对于作为中间件之一的DDS&#xff08;数据分发服务Data Distribution Service&#xff09;可能并不陌生&#xff1b;若没有…...

LibTorch中Windows系统环境配置及CUDA不可用问题解决

前言&#xff1a;本文对在Windows系统上进行LibTorch开发环境配置及相关问题解决做一个较为详细的记录&#xff0c;以便后续查询使用。 使用环境版本&#xff1a; Windows 11 Visual Studio 2022 CUDA 12.0 LibTorch 1.13.1_cu11.7 目录一、LibTorch简介二、LibTorch下载安装三…...

Java并发编程实战二

线程间的通讯方式 1.volitate(缓存一致性协议),synchronize,lock(都保证可见性) 2.wait.notify,await(),signal(前两个是Object&#xff0c;后两个属于lock) 3.管道输入、输出流 (示例代码&#xff1a;PipeInOut.java)&#xff08;目前几乎没人使用&#xff09; 管道输入/输…...

Linux中最基本的命令ls的用法有哪些?

Linux是一种流行的操作系统&#xff0c;被广泛应用于服务器和个人电脑。Linux命令行界面是使用Linux操作系统的关键。其中一个最基本的命令是"ls"命令&#xff0c;该命令用于列出指定目录中的所有文件和子目录。在这篇文章中&#xff0c;我们将探讨ls命令及其各种用途…...

第 100002(十万零二)个素数是多少?

题目描述 素数就是不能再进行等分的整数。比如7&#xff0c;11。而 9 不是素数&#xff0c;因为它可以平分为 3 等份。一般认为最小的素数是2&#xff0c;接着是 3&#xff0c;5&#xff0c;... 请问&#xff0c;第 100002(十万零二)个素数是多少&#xff1f; 请注意&#xff1…...

Lua迭代器

Lua迭代器 迭代器&#xff08;iterator&#xff09;是一种对象&#xff0c;它能够用来遍历标准模板库容器中的部分或全部元素&#xff0c;每个迭代器对象代表容器中的确定的地址。 在 Lua 中迭代器是一种支持指针类型的结构&#xff0c;它可以遍历集合的每一个元素。 泛型 f…...

同步与互斥之信号量

目录 1、信号量用于线程的互斥 验证 2、信号量用于线程的同步 验证 3、无名信号量用于进程间互斥 代码一 代码二 验证 4、有名信号量 用于进程间同步和互斥 验证 信号量广泛用于进程或线程间的同步和互斥&#xff0c;信号量本质上是一个非负的整数计数器&#xff0c;它…...

如何当个优秀的文档工程师?从 TC China 看技术文档工程师的自我修养

本文系 NebulaGraph Community Academic 技术文档工程师 Abby 的参会观感&#xff0c;讲述了她在中国技术传播大会分享的收获以及感悟。 据说&#xff0c;技术内容领域、传播领域的专家和决策者们会在中国技术传播大会「tcworld China 2022」大会上分享心得。作为一名技术文档工…...

如何学习k8s

学习Kubernetes可以遵循以下步骤&#xff1a; 了解Kubernetes的基本概念和架构。学习Kubernetes前&#xff0c;需要了解它的基本概念和组成部分&#xff0c;包括Pod、Service、ReplicaSet、Deployment、Namespace等等&#xff0c;同时也需要了解Kubernetes的整体架构和工作原理…...

【SSM】MyBatis(十.动态sql)

文章目录1.if2.where3.trim4.set5. choose when otherwise6.foreach6.1 批量删除6.2 批量增加7.sql1.if <select id"selectByMultiCondition" resultType"Car">select * from t_car where 1 1<if test"brand ! null and brand ! ">…...

最近很多人都在说 “前端已死”,讲讲我的看法

转自 : 掘金 作者 : Ethan_Zhou 现状 我记得去年脉脉的论调还都是 客户端已死&#xff0c;前后端还都是一片祥和&#xff0c;有秀工资的&#xff0c;有咨询客户端转前端的&#xff0c;怎么最近打开脉脉一看&#xff0c;风向变了&#xff1f; 随便刷几下&#xff0c;出来的信息…...

大家好,我是火旺技术

大家好&#xff0c;我是火旺技术 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用。这其中&#xff0c;家乡特色推荐的网络应用已经成为外国家乡推荐系统的一种很普遍的方式。不过&#xff0c;在国内&#xff0c;管理网站可能还处于起步阶段。 …...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

VisualXML全新升级 | 新增数据库编辑功能

VisualXML是一个功能强大的网络总线设计工具&#xff0c;专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑&#xff08;如DBC、LDF、ARXML、HEX等&#xff09;&#xff0c;并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...

32单片机——基本定时器

STM32F103有众多的定时器&#xff0c;其中包括2个基本定时器&#xff08;TIM6和TIM7&#xff09;、4个通用定时器&#xff08;TIM2~TIM5&#xff09;、2个高级控制定时器&#xff08;TIM1和TIM8&#xff09;&#xff0c;这些定时器彼此完全独立&#xff0c;不共享任何资源 1、定…...

《信号与系统》第 6 章 信号与系统的时域和频域特性

目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...

6.9-QT模拟计算器

源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...

【51单片机】4. 模块化编程与LCD1602Debug

1. 什么是模块化编程 传统编程会将所有函数放在main.c中&#xff0c;如果使用的模块多&#xff0c;一个文件内会有很多代码&#xff0c;不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里&#xff0c;在.h文件里提供外部可调用函数声明&#xff0c;其他.c文…...

Python第七周作业

Python第七周作业 文章目录 Python第七周作业 1.使用open以只读模式打开文件data.txt&#xff0c;并逐行打印内容 2.使用pathlib模块获取当前脚本的绝对路径&#xff0c;并创建logs目录&#xff08;若不存在&#xff09; 3.递归遍历目录data&#xff0c;输出所有.csv文件的路径…...