首页 > 其他分享 >一个事务插入,另外一个事务更新操作,是否会更新成功?

一个事务插入,另外一个事务更新操作,是否会更新成功?

时间:2023-04-13 15:37:27浏览次数:27  
标签:INFO ... 事务 java 04 8099 插入 更新

1.前言

同样另外一个非常有意思的题目,值得我们思考。大概背景是这个样子的。如果有一个事务A进行插入 id > 100, 同时另外一个事务B进行更新update id > 100。那么事务B是否会更新成功。我们来画一个时序图:

time 事务A 事务B 备注
T1 insert id > 100 set status = 1
T2 update id > 100 set status = 2
T3 最后id > 100 status是为1 还是为2呢

2.代码

我们从事务的四个隔离性来分别讨论这个问题。所有代码如下,仅仅是隔离性级别修改。修改是status状态。
以下所有操作类似于打开两个浏览器,首先请求事务A,事务A执行过程中,在请求事务B,观察结果。

  1. 事务A 进行插入
@RequestMapping("/test/publish/submit")
public String testPublish1() {
	log.info("start...");
	transactionTemplate.execute(new TransactionCallback<String>() {
		@Override
		public String doInTransaction(TransactionStatus status)  {
			for (long i = 1000; i < 3000; i++) {
				TElement element = new TElement();
				element.setfElementId(i);
				element.setfElementName("111");
				element.setfElementStatus((byte) 1);
				mapper.insertSelective(element);
			}
			return "OK";
		}
	});
	log.info("end...");
	return "ok";
}
  1. 事务B 进行更新
@RequestMapping("/test/publish/submit2")
public String testPublish2() {
	log.info("start...");
	transactionTemplate.execute(new TransactionCallback<String>() {
		@Override
		public String doInTransaction(TransactionStatus status)  {
			// @Update({"UPDATE t_element SET f_element_status=#{status} WHERE f_element_id > #{elementId}"})
			mapper.update(1000L, (byte) 2);
			return "OK";
		}
	});
	log.info("end...");

	return "ok";
}

2.1读未提交(READ UNCOMMITTED)级别

经过以上步骤测试,我们得出了如下日志

[INFO  2023-04-13 11:39:29.941] [http-nio-8099-exec-2] [df9c9572-a906-4f5c-91a2-c1fb4a87adcf] - [TransactionInsertUpdateTest.java.testPublishInsert:36] [start...]

[INFO  2023-04-13 11:39:31.708] [http-nio-8099-exec-3] [5651390e-f3be-4d35-81dc-cc7bb0062f40] - [TransactionInsertUpdateTest.java.testPublishUpdate:57] [start...]
[INFO  2023-04-13 11:39:31.760] [http-nio-8099-exec-3] [5651390e-f3be-4d35-81dc-cc7bb0062f40] - [TransactionInsertUpdateTest.java.testPublishUpdate:66] [end...]

[INFO  2023-04-13 11:39:42.952] [http-nio-8099-exec-2] [df9c9572-a906-4f5c-91a2-c1fb4a87adcf] - [TransactionInsertUpdateTest.java.testPublishInsert:50] [end...]

我们可以看到事务A在29秒开始执行,并且在42秒执行完成。
事务B在31秒开始执行,并且没有阻塞,立刻执行完成。
我们再来观察以下数据库中的数据,我们发觉status=1,也就是事务B没有更新成功
因此在READ UNCOMMITTED下,事务会有问题。
image

2.2读已提交(READ COMMITTED)

经过以上步骤测试,我们得出了如下日志。我们可以看到在RC级别下,出现了和READ UNCOMMITTED同样的现象。
具体原因如上,就是没有加锁。

[INFO  2023-04-13 11:46:59.684] [http-nio-8099-exec-3] [a11f29f2-0658-42b4-8eba-28b5f94f9037] - [TransactionInsertUpdateTest.java.testPublishInsert:36] [start...]

[INFO  2023-04-13 11:47:01.029] [http-nio-8099-exec-2] [a9d04f6e-4efe-4ed7-a2df-c2454d8d7946] - [TransactionInsertUpdateTest.java.testPublishUpdate:57] [start...]
[INFO  2023-04-13 11:47:01.090] [http-nio-8099-exec-2] [a9d04f6e-4efe-4ed7-a2df-c2454d8d7946] - [TransactionInsertUpdateTest.java.testPublishUpdate:66] [end...]

[INFO  2023-04-13 11:47:12.574] [http-nio-8099-exec-3] [a11f29f2-0658-42b4-8eba-28b5f94f9037] - [TransactionInsertUpdateTest.java.testPublishInsert:50] [end...]

2.3可重复读(REPEATABLE READ)

经过以上步骤测试,我们得出了如下日志。注意以下testPublishUpdate日志和以上日志的不同。

[INFO  2023-04-13 11:50:47.428] [http-nio-8099-exec-3] [83cac49b-f44e-44bd-a8ef-9d60714016f6] - [TransactionInsertUpdateTest.java.testPublishInsert:36] [start...]
[INFO  2023-04-13 11:50:48.851] [http-nio-8099-exec-2] [f66d62af-aa3f-4d3e-9f66-c97307d6e38e] - [TransactionInsertUpdateTest.java.testPublishUpdate:57] [start...]


[INFO  2023-04-13 11:50:53.872] [http-nio-8099-exec-3] [83cac49b-f44e-44bd-a8ef-9d60714016f6] - [TransactionInsertUpdateTest.java.testPublishInsert:50] [end...]
[INFO  2023-04-13 11:50:53.895] [http-nio-8099-exec-2] [f66d62af-aa3f-4d3e-9f66-c97307d6e38e] - [TransactionInsertUpdateTest.java.testPublishUpdate:66] [end...]

在事务A insert的时候,事务B update的时候阻塞了。这时候其实是间隙锁发挥了作用,也就是必须等事务A执行完毕之后,事务B才会获取锁,去update更新。那这时候就会更新成功了。数据库数据如下:

image

2.4序列化

隔离级别最严格的级别。同2.3会阻塞然后更新成功。

3.结论

在隔离级别为 读未提交(READ UNCOMMITTED)以及读已提交(READ COMMITTED)情况下,会出现事务更新失败的情况。
本质上就是没有加锁导致的,而在RR级别,给事务A加上了间隙锁,事务B必须等待才能update成功。是用了锁的的方式来解决的,但可能存在效率的问题。所以锁尽量细化,比如行锁 > 间隙锁 > 记录锁 > 表锁。都是平衡效率以及安全的一种手段。

标签:INFO,...,事务,java,04,8099,插入,更新
From: https://www.cnblogs.com/wenbochang/p/17314159.html

相关文章

  • git 更新代码错误 Your local changes to the following files would be overwritten
    当gitpull时提示 Yourlocalchangestothefollowingfileswouldbeoverwrittenbymerge idea中撤销当前本地本次提交 ......
  • 【BUG】ExtJS 的Tab Reorder 插件持续更新布局问题解决办法 (Solution to layout issue
    更新记录2023年4月13日初始化。ExtJS教程汇总:https://www.cnblogs.com/cqpanda/p/16328016.html问题不停的拖动tab栏,会不断更新布局。Draggingthetabbarcontinuouslywillupdatethelayoutconstantly.解决办法进入ExtJS包,打开ux目录下的BoxReorderer.js文件,找......
  • vue中父子组件调用之头像更新
    问题描述:修改图像的功能,要实现的功能是这样的:点击确认按钮,然后连带着上面的头像也更新,是不是很简单,只需要一个刷新就行,但是事实上没这么简单,因为我的这个项目涉及到三个组件 这里面中间是一个子路由,然后上面是一个组件,左边是一个组件  然后这个就涉及到子父组件传值,这......
  • 如何解决更新WordPress需要访问您网页服务器的权限
    今天更新wordpress版本时网站后台提示“要执行请求的操作,WordPress需要访问您网页服务器的权限”,更新插件也提示,更新主题也提示。后来百度查询了一下,找到了解决办法,只需要找到wp-config.php这个文件,在最后面加上如下代码就能解决问题,至于是什么原因造成的并不清楚。define(“FS_......
  • spring事务里面开启线程插入,报错了是否会回滚?
    1.前言一道非常有意思的面试题目。大概是这样子的,如果在一个事务中,开启线程进行插入更新等操作,如果报错了,事务是否会进行回滚2.代码示例1@RequestMapping("/test/publish/submit")publicStringtestPublish1(){ log.info("start..."); transactionTemplate.execute(new......
  • 读取Excel表格数据做接口自动化测试并回写执行结果(待完善更新)
     待测试接口:代码脚本:控制台日志:执行结果:后续待完善:Excel表格增加请求方式(常用方式POST/GET/PUT)列;根据Excel表格内容(请求头Header、请求参数Parameter、请求体Body)发起请求;根据Excel表格内容(期望响应码、期望响应内容)与实际响应内容校验;考虑更多应用场景,增加判断......
  • 读取Excel表格数据做接口自动化测试并回写执行结果(待完善更新)11
    读取Excel表格数据做接口自动化测试并回写执行结果(待完善)待测试接口:代码脚本:控制台日志:执行结果:后续待完善:Excel表格增加请求方式(常用方式POST/GET/PUT)列;根据Excel表格内容(请求头Header、请求参数Parameter、请求体Body)发起请求;根据Excel表格内容(期望响应码、期望响应内容)与实际响......
  • Mysql四种事务隔离级别
    先了解一下事务的四大特性:ACID原子性(Atomicity)原子性就是不可拆分的特性,要么全部成功然后提交(commit),要么全部失败然后回滚(rollback)。MySQL通过RedoLog重做日志实现了原子性,在将执行SQL语句时,会先写入redologbuffer,再执行SQL语句,若SQL语句执行出错就会根据redologbuffer中的......
  • fork 了别人的仓库后如何保持同步更新
    给fork配置一个remotegitremote-v2.配置远程分支地址[email protected].将上游分支提交点提交到本地。gitfetchupstream4.切换到本地分支gitcheckouttrunk-develop-v2.0-liwei找到对应的远程分支进行合并gitmergeupstream/trunk-develop......
  • Android sqlite 数据库查询,插入,删除,更新demo<第1章>
    //20140424创建数据库帮助类DataBaseHelper,继承SQLiteOpenHelper, 1. 编写构造函数,实现数据库创建;publicstaticfinalStringTAG="ListViewActivity";privatestaticintVERSION=1;privatestaticfinalStringTABLE_NAME="user1";privatestaticfinalSt......