多线程怎么共用一个事务
文章目录
- 场景
- 分析
- 测试
- 对应的其他类我并没有贴出来,因为大家可以自己找个项目走一波
- 测试testSession
- 测试testTransaction
- 注意使用同一个sqlsession会导致线程安全问题,testSession方法就是在另外线程里面能读取到数据库里面没有的数据.但是有时候业务就是这么奇怪.
- 扩展总结
场景
有一天邱大神问我
业务很简单,比如:我新增一个user使用事务,然后再这个事务里面创建了个线程,新增另外一个表的数据
我要在第二个事务里面查询到第一个事务里面的user新增的数据
分析
如果在同一个事务里面的话,那么先提交了一个用户,后面的线程查询就能查询得到.
那只需要这个方法使用的都是同一个SqlSession即可;
测试
创建个SqlContext获取SqlSession:
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;@Component
public class SqlContext {@Resourceprivate SqlSessionTemplate sqlSessionTemplate;public SqlSession getSqlSession(){SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory();return sqlSessionFactory.openSession();}
}
好比我有个config表就建的key,value
CREATE TABLE `config` (`id` int NOT NULL AUTO_INCREMENT,`config_key` varchar(20) NOT NULL,`config_value` varchar(500) NOT NULL,`modified_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,`remark` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '备注',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
两个测试方法,
- 一个是testSession,通过sqlContext获取SqlSession,通过sqlSession获取ConfigDao,然后多线程方法内部也使用这个ConfigDao,然后手动提交事务回滚事务.然后分别先进行修改数据,然后在新增一条数据,另外一条线程内部进行查询数据,并且查询最新的一条数据.
- 一个是testTransaction,通过spring的声明式事务,也是先进行修改数据,然后在新增一条数据,另外一条线程内部进行查询数据,并且查询最新的一条数据.
对应的其他类我并没有贴出来,因为大家可以自己找个项目走一波
测试testSession
@Override@SneakyThrowspublic Config testSession(Long id) {// 获取数据库连接,获取sqlSessionSqlSession sqlSession = sqlContext.getSqlSession();Connection connection = sqlSession.getConnection();try {// 设置手动提交connection.setAutoCommit(false);ConfigDao configDao = sqlSession.getMapper(ConfigDao.class);Config config = configDao.selectById(id);String testSession = "testSession:" + RandomUtil.randomString(3);config.setConfigValue(testSession);log.info("修改的value为:{}", testSession);configDao.updateById(config);Config insertConfig = new Config();insertConfig.setConfigKey(new DateTime().toString("HH:mm:ss"));insertConfig.setConfigValue(new DateTime().toString("HH:mm:ss"));configDao.insert(insertConfig);log.info("新增的id:" + insertConfig.getId());//另外一条线程执行CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {//让最后一个线程抛出异常Config config1 = configDao.selectById(id);log.info("内部查询的value:{}", config1.getConfigValue());QueryWrapper<Config> wrapper = new QueryWrapper<>();wrapper.orderByDesc("id").last("limit 1");Config config2 = configDao.selectOne(wrapper);log.info("查询最新的id:" + config2.getId());});future.get();connection.commit();log.info("修改完毕");return config;} catch (Exception e) {connection.rollback();log.info("error", e);throw e;} finally {connection.close();}}
返回结果:跟我们预想的一样,相当于使用的同一个事务,可以看看打印的线程名称不同,一个是main,一个是onPool-worker-9;
2023-09-07 15:15:02.238 INFO 2448 [ main] c.s.s.service.impl.ConfigServiceImpl [52] : 修改的value为:testSession:owg
2023-09-07 15:15:02.354 INFO 2448 [ main] c.s.s.service.impl.ConfigServiceImpl [59] : 新增的id:10
2023-09-07 15:15:02.365 INFO 2448 [onPool-worker-9] c.s.s.service.impl.ConfigServiceImpl [66] : 内部查询的value:testSession:owg
2023-09-07 15:15:02.399 INFO 2448 [onPool-worker-9] c.s.s.service.impl.ConfigServiceImpl [71] : 查询最新的id:10
2023-09-07 15:15:02.407 INFO 2448 [ main] c.s.s.service.impl.ConfigServiceImpl [76] : 修改完毕
测试testTransaction
@Override@Transactional@SneakyThrowspublic Config testTransaction(Long id) {Config config = baseMapper.selectById(id);String testSession = "testSession:" + RandomUtil.randomString(3);config.setConfigValue(testSession);log.info("修改的value为:{}", testSession);baseMapper.updateById(config);Config insertConfig = new Config();insertConfig.setConfigKey(new DateTime().toString("HH:mm:ss"));insertConfig.setConfigValue(new DateTime().toString("HH:mm:ss"));baseMapper.insert(insertConfig);log.info("新增的id:" + insertConfig.getId());//另外一条线程执行CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {//让最后一个线程抛出异常Config config1 = baseMapper.selectById(id);log.info("内部查询的value:{}", config1.getConfigValue());QueryWrapper<Config> wrapper = new QueryWrapper<>();wrapper.orderByDesc("id").last("limit 1");Config config2 = baseMapper.selectOne(wrapper);log.info("查询最新的id:" + config2.getId());});future.get();log.info("修改完毕");return config;}
返回结果:
2023-09-07 15:18:44.025 INFO 29104 [ main] c.s.s.service.impl.ConfigServiceImpl [94] : 修改的value为:testSession:pl8
2023-09-07 15:18:44.171 INFO 29104 [ main] c.s.s.service.impl.ConfigServiceImpl [101] : 新增的id:11
2023-09-07 15:18:44.189 INFO 29104 [onPool-worker-9] c.s.s.service.impl.ConfigServiceImpl [108] : 内部查询的value:testSession:owg
2023-09-07 15:18:44.242 INFO 29104 [onPool-worker-9] c.s.s.service.impl.ConfigServiceImpl [113] : 查询最新的id:10
2023-09-07 15:18:44.243 INFO 29104 [ main] c.s.s.service.impl.ConfigServiceImpl [117] : 修改完毕
注意使用同一个sqlsession会导致线程安全问题,testSession方法就是在另外线程里面能读取到数据库里面没有的数据.但是有时候业务就是这么奇怪.
扩展总结
可以看看我的mybatis的简单解析:
mybatis的源码解析:https://blog.csdn.net/qq_38366063/category_8574377.html
为什么DefaultSqlSession线程不安全?
首先由于JDBC的Connection对象本身不是线程安全的,而session中又只有一个connection,所以不是线程安全的
一次SqlSession的执行最终只会产生一个connection,所以我们设想一下,在两个线程通过同一个sqlsession来执行crud,那么就有可能,我先跑完的线程,把唯一的这一个连接给关闭掉,从而造成另一条线程的逻辑不被成功执行,所以在方法里面通过创建SqlSession来执行数据库操作是线程不安全的。就会导致testSession方法的现象.
为什么使用的mapper就不会出现线程安全问题?
因为注入到service类里面的mapper是MapperProxy的代理类,内部是SqlSessionTemplate,而SqlSessionTemplate是线程安全的,因为每次执行方法都会走SqlSessionInterceptor拦截器,创建一个新的SqlSession(其实是从当前事务之外得到一个SqlSession,如果没有就创造一个新的。然后,如果事务被打开,且事务管理器是SpringManagedTransactionFactory时,将得到的SqlSession同当前事务同步,也就是说开启了事务,那么SqlSession就是当前事务内的那个SqlSession,所有开启了事务仍有一级缓存,不开启事务那么每次都新建一个SqlSession,那么此时一级缓存就会失效)
相关文章:
多线程怎么共用一个事务
文章目录 场景分析测试对应的其他类我并没有贴出来,因为大家可以自己找个项目走一波测试testSession测试testTransaction 注意使用同一个sqlsession会导致线程安全问题,testSession方法就是在另外线程里面能读取到数据库里面没有的数据.但是有时候业务就是这么奇怪.扩展总结 场…...

scrollIntoView使用与属性详解
scrollIntoView 使用与属性详解 效果图如下图所示 如果要想让元素滚动到指定位置 window.onload function () {containerItems[6].scrollIntoView({ behavior: "smooth" }); };js 代码 const containerItems document.querySelectorAll(".container div&…...

【LeetCode热题100】--169.多数元素
169.多数元素 使用哈希表: class Solution {public int majorityElement(int[] nums) {int n nums.length;int m n/2;Map<Integer,Integer> map new HashMap<>(); //定义一个hashfor(int num:nums){Integer count map.get(num); //Map.get() 方法…...
LeetCode 面试题 10.01. 合并排序的数组
文章目录 一、题目二、C# 题解 一、题目 给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。 初始化 A 和 B 的元素数量分别为 m 和 n。 示例: 输入: A [1,2,3,0,0,0], m 3 B [2,5,6], n 3 输…...

揭秘OLED透明拼接屏的参数规格:分辨率、亮度与透明度全解析
作为一种新型的显示技术,OLED透明拼接屏在市场中正在迅速崭露头角,有很多知名品牌厂家能设计、开发、生产高品质的显示产品。 如尼伽、起鸿、康视界、LG、YCTIMES、腾裕等,这些品牌在显示技术领域拥有丰富的经验和声誉,以其卓越的…...

竞赛选题 深度学习YOLOv5车辆颜色识别检测 - python opencv
文章目录 1 前言2 实现效果3 CNN卷积神经网络4 Yolov56 数据集处理及模型训练5 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于深度学习YOLOv5车辆颜色识别检测 ** 该项目较为新颖,适合作为竞赛课题方向࿰…...

linux U盘无法使用,提示“Partition table entries are not in disk order“
问题: U盘在Windows上使用正常,在linux下无法使用fdisk -l 命令提示:Partition table entries are not in disk order $ fdisk -l Disk /dev/sdb: 525 MB, 525336576 bytes 17 heads, 59 sectors/track, 1022 cylinders Units cyl…...
HDLbits: Fsm ps2
本题目理解起来有点难,要观察题目中给的三个时序图,通过时序图可以发现,状态有四个:byte1、byte2、byte3,还有一个“?”状态。其中,byte1的下一个状态一定是byte2,byte2的下一个状态…...

【设计模式】八、桥接模式
文章目录 举例问题分析基本介绍桥接模式在 JDBC 的源码剖析桥接模式的注意事项和细节JDBC 举例 现在对不同手机类型的不同品牌实现操作编程(比如:开机、关机、上网,打电话等), 传统方法对应的类图: 问题分析 扩展性问题(类爆炸)ÿ…...

从零开始的stable diffusion
stable diffusion真的是横空出世,开启了AIGC的元年。不知你是否有和我一样的困惑,这AI工具好像并不是那么听话? 前言 我们该如何才能用好stable diffusion这个工具呢?AI究竟在stable diffusion中承担了什么样的角色?如…...
【Qt之QString】数值与进制字符串间的转换详解
在Qt中,可以使用QString类提供的一些方法来进行数值和进制字符串之间的转换。 以下是示例: 1. 将整数转换为进制字符串: QString类的number静态方法用于将整数转换为字符串表示,并且可以指定转换的进制。方法的定义如下&#x…...

Pytest单元测试框架 —— Pytest+Allure+Jenkins的应用
一、简介 pytestallurejenkins进行接口测试、生成测试报告、结合jenkins进行集成。 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高 allure-pytest是python的一个第三方…...

科普向丨语音芯片烧录工艺的要求
语音芯片烧录工艺要求烧录精度、速度、内存容量、电源稳定性、兼容性和数据安全性。这些要素需优化和控制以保证生产高效、稳定、安全并烧录出高质量的语音芯片。不同厂家生产的语音芯片在烧录工艺上存在差异,需相应设计和研发以实现兼容。 一、烧录精度 语音芯片烧…...
: 依赖: qtbase5-dev (= 5.12.8+dfsg-0ubuntu2.1) 但是它将不会被安装 或
有一些软件包无法被安装。如果您用的是 unstable 发行版,这也许是因为系统无法达到您要求的状态造成的。E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。_unstable发行版-CSDN博客 E: 无法修正错误&#x…...
Unity中Camera类实现坐标系转换的示例
1. 用于将世界坐标系转换为屏幕坐标系 using System.Collections; using System.Collections.Generic; using UnityEngine;public class Camer_Class_WorldTo : MonoBehaviour {// 用于将世界坐标系转换为屏幕坐标系//本脚本将完成一个案例实现 小球从远处过来Transform Sta…...
vue-按键修饰符
按键修饰符:主要用于监听键盘上的按钮被按下时,可触发对应的事件函数 v-on:keyup.修饰符.修饰符】、 .enter .tab .delete(针对delete和backspace两个按键) .esc .space .esc .space .up .down .left .right 系统修饰符必须按下才触发 .ctrl .alt .shift…...

[初始java]——java为什么这么火,java如何实现跨平台、什么是JDK/JRE/JVM
java的名言: ”一次编译、到处运行“ 一、编译语言与解释语言 编译: 是将整份源代码转换成机器码再进行下面的操作,最终形成可执行文件 解释: 是将源代码逐行转换成机器码并直接执行的过程,不需要生成目标文件 jav…...

R语言手动绘制NHANSE数据基线表并聊聊NHANSE数据制作亚组交互效应表的问题(P for interaction)
美国国家健康与营养调查( NHANES, National Health and Nutrition Examination Survey)是一项基于人群的横断面调查,旨在收集有关美国家庭人口健康和营养的信息。 地址为:https://wwwn.cdc.gov/nchs/nhanes/Default.aspx 在既往的…...
C++引用(起别名)
0.引用的概念 引用不是新定义一个变量,而是给已存在变量取了一个别名,从语法的角度来说编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。比如说你的名字和外号指的都是你本人。 void Test() {int a 10;int& ra …...

Ubuntu:VS Code IDE安装ESP-IDF【保姆级】(草稿)
物联网开发学习笔记——目录索引 Visual Studio Code(简称“VS Code”)是Microsoft向开发者们提供的一款真正的跨平台编辑器。 参考: VS Code官网:Visual Studio Code - Code Editing. Redefined 乐鑫官网:ESP-IDF …...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...