事务中的多线程引发的怪异现象
目标逻辑:
背景:对3条(多条)数据先进行审核通过、后发奖励操作。发奖动作不应影响审核并且实时性不高,所以在审核通过之后开启新线程进行发奖操作。
预期:数据状态有auditStatus(审核状态)与issueStatus(发奖状态),3条(多条)数据状态均从auditStatus更新为PASS(审核通过),issueStatus更新为SUCCESS(发放成功)或者FAIL(发放失败)。
做法:审核通过后开启新线程进行发放操作。代码的结构大致上是这样的
@Transactional(rollbackFor=Exception.class)
public void resolve(List<SettlementDTO> dtos){for(SettlementDTO dto : dtos){doSomething(dto);pass(dto);}
}public void pass(final SettlementDTO dto){dto.setAuditStatus("PASS");update(dto);dto.setVersion(dto.getVersion() + 1l);new Thread(new Runnable() {@Overridepublic void run() {doSomething(dto);dto.setIssueStatus("SUCCESS");update(dto);}}).start();
}
实际行为:3条(多条)数据审核通过,有时候1条有时候2条数据发放成功。
分析:
拿一条更新成功举例,
起初以为是多线程引起的线程管理的局部变量被其他线程篡改。于是把代码改成了这样,保证了每个线程改的是自己的局部变量。
@Transactional(rollbackFor=Exception.class)
public void resolve(List<SettlementDTO> dtos){for(SettlementDTO dto : dtos){doSomething(dto);pass(dto);}
}public void pass(SettlementDTO dto){dto.setAuditStatus("PASS");update(dto);dto.setVersion(dto.getVersion() + 1l);IssueThread issueThread = new IssueThread(dto);new Thread(issueThread).start();
}class IssueThread implements Runnable{private SettlementDTO dto;public IssueThread(final SettlementDTO dto) {this.dto = dto;}@Overridepublic void run() {doSomething(dto);dto.setIssueStatus("SUCCESS");update(dto);}
}
程序运行下来还是语刚才相同的结果。
日志逐一打印3条数据的dto发现,dto的id对应的version均是正确的,也就是说,线程内部的局部变量并没有被其他线程篡改。
于是把焦点放在了上面的事务上。
把事务注释掉后,3条(多条)数据的issueStatus均更新为了SUCCESS。
解释:
事务中开启新线程,新的线程的事务不受外面的大事务的控制,数据新开的事务。
代码执行完毕后(所有线程执行结束之前),数据库的操作均会在一个事务中提交。但是在此之前,多个线程已经有两个线程执行完毕,并提交了自己的事务,导致执行顺序的不一致。
举个栗子:
dto更新auditStatus=PASS时,version=1,dto更新issueStatus=SUCCESS时,version=2,
正常顺序执行下来没有问题,但是线程的事务在外围大事务之前提交,即先用version=2更新issueStatus=SUCCESS,后用version=1更新auditStatus=PASS,所以第一个语句执行失败,后一个语句执行成功。
验证:
为确保线程提交事务的顺序在大事务之后,线程均先休息2s再开始执行。
class IssueThread implements Runnable{private SettlementDTO dto;public IssueThread(final SettlementDTO dto) {this.dto = dto;}@Overridepublic void run() {try {sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}doSomething(dto);dto.setIssueStatus("SUCCESS");update(dto);}
}
这样子,3条数据均发奖成功(issueStatus=SUCCESS)。
事务中的多线程引发的怪异现象相关推荐
- Python中的id()函数_怪异现象
python中有一个内置函数叫id(obj) ,可以获取obj在python中的实际内存,比如: >>> id(13) 8791398340000 >>> id(i ...
- delphi 字符串处理中的怪异现象与处理
1, 怪异现象:字符串相加操作不正常! 以上代码,明显输出字符串应含有后缀".jpg",但实际输出却不含后缀(如下),字符串加法操作似乎不起作用了! 采用showMessage进行 ...
- 在.NET客户端程序中使用多线程
在.NET客户端程序中使用多线程通常认为在编写程序中用到多线程是一个高级的编程任务,容易发生错误.在本月的栏目中,我将在一个Windows窗体应用程序中使用多线程,它具有实际的意义,同时尽量使事情简单 ...
- 第13章 C#中的多线程
第13章多线程 13.1 线程概述 计算机的操作系统多采用多任务和分时设计.多任务是指在一个操作系统中开以同时运行多个程序.例如,可以在使用QQ聊天的同时听音乐,即有多个独立的任务,每个任务对应一个进 ...
- java怎样获取线程的进度_java中的多线程——进度2
多线程总结: 1,进程和线程的概念. |--进程:是一块包含了某些资源的内存区域.操作系统利用进程把它的工作划分为一些功能单元: 最小的内存单元: 是具有一定独立功能的程序关于某个数据集合上的一次运行 ...
- iOS 开发中的多线程
线程.进程 什么是线程.进程 有的人说进程就像是人的脑袋,线程就是脑袋上的头发~~.其实这么比方不算错,但是更简单的来说,用迅雷下载文件,迅雷这个程序就是一个进程,下载的文件就是一个线程,同时下载 ...
- 一起谈.NET技术,在.NET Workflow 3.5中使用多线程提高工作流性能
最近在工作上碰到一个性能问题,由于项目是基于SOA的架构,使得整个系统完全依赖于各种各样的Service,其中用于处理业务逻辑的Business Services全部都用.NET Workflow 3 ...
- 【worker】js中的多线程
因为下个项目中要用到一些倒计时的功能,所以就提前准备了一下,省的到时候出现一下界面不友好和一些其他的事情.正好趁着这个机会也加深一下html5中的多线程worker的用法和理解. Worker简介 J ...
- ArcGIS Engine 中的多线程使用
转自原文ArcGIS Engine 中的多线程使用 一直都想写写AE中多线程的使用,但一直苦于没有时间,终于在中秋假期闲了下来.呵呵,闲话不说了,进入正题! 大家都了解到ArcGIS中处理大数据量时速 ...
- Java 程序中的多线程
在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为 Java 编程语言提供了语言级的支持.本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观.读完本文以后,用户应 ...
最新文章
- 【Groovy】字符串 ( 字符串类型变量定义 | 字符类型变量定义 )
- python3中的type与object
- java导包及注意事项_STS导项目的顺序及注意事项
- yum安装nginx php mysql_yum安装nginx+mysql+php
- php背景音乐合成,录音加背景音乐要怎么做 如何将两个音乐融合
- 透过WebGL 3D看动画Easing函数本质
- 【TODO】HTML label
- java day29【DBC基本概念 、快速入门 、对JDBC中各个接口和类详解】
- java提取(获取)博客信息(内容)
- MySQL binlog_format (Mixed,Statement,Row)
- SQL安装过程中出现的错误解决
- word模板填充数据,导出PDF
- [BZOJ4134][JZOJ4401]ljw和lzr的hack比赛
- HTML5和CSS3 API文档分享
- HotFix移动热修复详解
- json vue 对象转数组_json 将对象转化成数组第二种方式
- (二十一)sift 特征点检测
- MOOC高级语言程序设计第七章课后作业
- php羊5年死一次,已知一只羊有7岁寿命,且在2、3、5岁时产下1只小羊(不管公母,...
- ABAP程序系统字段中英文详解_华亭慧剑译
热门文章
- 【STM32】 STM32单片机IO引脚配置方式
- 2021 年使用人数最多的5款主流前端框架点评
- 中铁二局全面推行建筑工地务工人员实名制管理
- 有哪些免费的发布信息网站?
- windows10电脑发现不了网络计算机,Win10电脑无法开启网络发现怎么解决?
- Google Earth Engine 入门1 GEE账号注册
- RationalDMIS 2020 CAD模型坐标系转换(山涧果子)2021
- 计算机c盘用户爆满,电脑C盘又爆满了?这招让你一键清除十几G内存
- python自学1.2-运算符和表达式
- 【有利可图网】PS实战系列:PS+SAI把照片制成唯美手绘效果