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

article/2023/6/4 15:47:48

@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 任务,返回执行完成的返回值

http://www.ngui.cc/article/show-1007589.html

相关文章

记一次前端cookie冲突,导致同一个浏览器其他系统被踢下线问题分享

背景: 首先我在是公司的一个职能部门&#xff0c;所做的软件主要是服务于公司内部员工使用&#xff0c;员工可以通过工号来进行登录&#xff0c;也可以通过其他方式登录&#xff0c;所以整个公司提供了一个统一身份管理平台来员工身份认证、权限进行集中式的管理&#xff0c;实…

三、Trino406系列 之 客户端

文章目录前言客户端命令行要求条件客户端安装Running the CLITLS/HTTPSJDBC驱动需求条件安装Registering and configuring the driverConnectingConnection parametersParameter reference前言 https://trino.io/docs/current/client/cli.html 客户端是向trino server提交sql查…

华为OD机试题【字符匹配】用 Java 解 | 含解题说明

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典本篇题目:字符匹配 题目 给你一个字符串…

Golang流媒体实战之一:体验开源项目lal

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 关于《Golang流媒体实战》 因为工作需要&#xff0c;开始了流媒体开发学习&#xff0c;于是打算选择一个Go版本的开源流媒体服务器作为学习方向lal是个不错的…

OpenWrt开启IPV6设置教程

OpenWrt配置OpenWrt->网络->接口->全局网络选项->清空!WAN 接口配置1.网络->接口->WAN->高级设置2.不勾选 “使用内置的 IPv6 管理”3.“Obtain IPv6-Address”设置为 自动。LAN 接口设置网络->接口->LAN->高级设置不勾选 “使用内置的 IPv6 管理…

TENER: Adapting Transformer Encoder for Named Entity Recognition 笔记

TENER: Adapting Transformer Encoder for Named Entity RecognitionAbstract&#xff08;摘要&#xff09;1 Introduction&#xff08;介绍&#xff09;2 Related Work&#xff08;相关工作&#xff09;2.1 Neural Architecture for NER&#xff08;NER 的神经网络架构&#x…

【实战】16.Vue Router 入门

简介 vue-router 是 Vue.js 官方提供的路由管理器,用于实现单页应用(Single Page Application, SPA)中的视图切换和页面导航。 vue-router 基于 Vue.js 的组件化思想,将路由信息抽象成组件,可以通过声明式的方式定义路由,将路由与组件映射起来,同时还支持路由导航守卫、…

实验十 图着色问题

《算法设计与分析》实验报告 所在院系 计算机与信息工程学院 学生学号 学生姓名 年级专业 2020级计算机科学与技术 授课教师 彭绪富 学 期 2022-2023学年第一学期 提交时间 2022年11月16日 目录 实验十-1&#xff1a;图着色问题 一、实验目的…

蓝桥杯刷题冲刺 | 倒计时14天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;马上就要蓝桥杯了&#xff0c;最后的这几天尤为重要&#xff0c;不可懈怠哦&#x1f43e; 文章目录1.最长递增2.走迷宫3.解立方根4.回文特判5.修改数组1.最长递增 题目 链接&#xff1a; 最长递增…

pip安装及国内源更换

# pip安装 python3&#xff1a; curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py python3 get-pip.py python2: curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip2.py python2 get-pip2.py # pip国内的一些镜像 阿里云 http://mirrors.aliyu…