MySQL可重复读隔离级别下,乐观锁为什么可以生效?

这篇具有很好参考价值的文章主要介绍了MySQL可重复读隔离级别下,乐观锁为什么可以生效?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

今天蹦出一个很蠢的问题,来记录一下
MySQL在可重复读事务隔离级别下,通过版本号实现的乐观锁可以生效吗?
举个例子:开启了两个事务一和二,在事务一中对某条数据进行了修改,版本号发生变化。但是在事务二中,查询这条记录的版本号,并没有发生变化,怎么确定这条数据是否被其他事务修改了呢?

原因是在可重复读隔离级别下,分为快照读当前读,update是当前读,而不是快照读,因而可以读取到最新的版本号。

快照读,读取的是开启事务一瞬间快照的数据,当前读可以读取到其他事务已经提交的数据。在可重复读隔离级别下,select使用的是快照读,当其他事务已经提交时,当前事务还是读取的快照数据,update更新时 通过where选中数据时,使用是当前读,读取的是当前的数据。所以在多个事务中,当其他事务修改了数据,版本号发生了变化,即使当前事务读取不到版本号的变化,但是在更新的时候,根据版本号更新数据时,选不到数据,会更新失败。

为什么要引入锁?肯定是避免多个线程修改一个资源,引发的并发问题,破坏数据一致性问题。下面看个例子,money记录一个存钱罐金额,存钱罐中的钱可以多个用户取出。下面是初数据:

mysql> select * from money;
+----+--------+
| id | money  |
+----+--------+
|  1 | 100.00 |
+----+--------+
1 row in set (0.00 sec)

开启两个事务,每个事务判断余额充足的情况下,取出金额:
事务一

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from money;
+----+--------+
| id | money  |
+----+--------+
|  1 | 100.00 |
+----+--------+
1 row in set (0.00 sec)

事务二

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from money;
+----+--------+
| id | money  |
+----+--------+
|  1 | 100.00 |
+----+--------+
1 row in set (0.00 sec)

每个事务判断金额都充足,事务一取出90
事务一

mysql> update money set money = money-90 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from money;
+----+-------+
| id | money |
+----+-------+
|  1 | 10.00 |
+----+-------+
1 row in set (0.00 sec)

事务二再次查询数据库,发现金额并没有减少,原因就是Select读取的是快照数据,然后事务二也开始取钱,
事务二

mysql> select * from money;
+----+--------+
| id | money  |
+----+--------+
|  1 | 100.00 |
+----+--------+
1 row in set (0.00 sec)

mysql>  update money set money = money-90 where id = 1;

但是update时,数据库阻塞,原因是事务一并没有提交事务,在事务二中拿不到行级锁。下面我们提交事务一,释放锁
事务一

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

事务二再次查询数据库,金额还是100,再次取钱试试
事务二

mysql> select * from money;
+----+--------+
| id | money  |
+----+--------+
|  1 | 100.00 |
+----+--------+
1 row in set (0.00 sec)

mysql>  update money set money = money-90 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

数据更新成功。提交事务吧
事务二

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

让我们查询一下数据最后的结果是怎样的


mysql> select * from money;
+----+--------+
| id | money  |
+----+--------+
|  1 | -80.00 |
+----+--------+
1 row in set (0.00 sec)

意料之中,并发问题,数据一致性被破坏。
下面让我们增加一个乐观锁试试吧。增加version版本号字段,记录数据版本

mysql> alter table money add version int(11) after money;
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> update money set version = 0 , money = 100 where id =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from money;
+----+--------+---------+
| id | money  | version |
+----+--------+---------+
|  1 | 100.00 |       0 |
+----+--------+---------+
1 row in set (0.00 sec)

同样开启两个事务
事务一

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

事务二

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

下面事务一开始取钱,更新数据时根据快照数据版本号更新,并且更改数据时顺带更新数据版本号。
事务一

mysql> select * from money;
+----+--------+---------+
| id | money  | version |
+----+--------+---------+
|  1 | 100.00 |       0 |
+----+--------+---------+
1 row in set (0.00 sec)

mysql> update money set money = money-90,version = version+1 where id = 1 and version = 0;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from money;
+----+-------+---------+
| id | money | version |
+----+-------+---------+
|  1 | 10.00 |       1 |
+----+-------+---------+
1 row in set (0.00 sec)

此时如果事务二也想修改数据是修改不成功的,因为事务一没有释放锁,事务二阻塞
事务二

mysql> select * from money;
+----+--------+---------+
| id | money  | version |
+----+--------+---------+
|  1 | 100.00 |       0 |
+----+--------+---------+
1 row in set (0.00 sec)

mysql> update money set money = money-90,version = version+1 where id = 1 and version = 0;

事务一提交事务
事务一

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

此时在事务二中更新数据,更改行数为0,找不到id=1,version=0 的记录

mysql> update money set money = money-90,version = version+1 where id = 1 and version = 0;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0

原因就是update是当前读,读取的是最新的数据,version已经变成了1。
select读取的是快照读,读取的是version还是0。
数据版本号发生了变化,更新失败,事务二回滚,再次查询数据,读取到新数据

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from money;
+----+-------+---------+
| id | money | version |
+----+-------+---------+
|  1 | 10.00 |       1 |
+----+-------+---------+
1 row in set (0.00 sec)

在MybatisPlus中,乐观锁实现原理同样是给数据库增加version版本号,我们修改数据时,会自动在update语句set后添加version = version + 1 ,where后面增加version = 旧版本号。文章来源地址https://www.toymoban.com/news/detail-733176.html

到了这里,关于MySQL可重复读隔离级别下,乐观锁为什么可以生效?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WebSocket 是什么原理?为什么可以实现持久连接?

    WebSocket 是一种用于实现持久连接的通信协议,它的原理和工作方式相对复杂,但我们可以尝试以尽可能简单和清晰的方式来解释它。 WebSocket 的原理 在理解 WebSocket 的工作原理之前,我们首先要了解 HTTP 协议的短连接性质。在传统的 HTTP 通信中,客户端发送一个请求到服务器

    2024年02月05日
    浏览(63)
  • 为什么单片机可以直接烧录程序的原因是什么?

    单片机(Microcontroller)可以直接烧录程序的原因主要有以下几点: 集成性:单片机是一种高度集成的芯片,内部包含了处理器核心(CPU)、存储器(如闪存、EEPROM、RAM等)、输入/输出接口(如GPIO、UART、SPI、I2C等)以及时钟电路等功能模块。这种高度集成的设计使得单片机能

    2024年02月16日
    浏览(57)
  • 20 信任链:为什么可以相信一个 HTTPS 网站?

    现实的生活当中,如果想证明一份合同没有被修改过,人们会在合同上盖一个齐缝章,并附上自己的签名。签名和盖章其实是一个含义,目的是证明自己签署过某份协议,而且一经签署,协议就不能再变更。 如果想阻止一份合同被修改,最容易想到的方式是加密 。合同一旦

    2024年02月21日
    浏览(60)
  • Linux中vim为什么直接可以操作jar包

    今天上线遇到了令人迷惑的问题,宽哥大佬排查的时候用vim直接查看了jar包,感觉很神奇,所以查了查资料; 学无止境!! JAR 文件的本质: JAR(Java ARchive)文件是 Java 平台上用于封装 Java 类文件、相关的元数据和资源文件的压缩包。JAR 文件使用了 ZIP 文件格式进行压缩和存

    2023年04月26日
    浏览(53)
  • 路由器劫持是什么意思为什么要劫持路由器有哪些方法可以防范

    继“棱镜门”事件之后,网络安全也随之被各大媒体关注,近段时间有不少媒体报道,全球拥有大量的路由器遭入侵、路由器被劫持等等。另外在如今越来越多的无线网络环境中,蹭网也是常常被人们提及,那么路由器劫持是什么意思?怎么看路由器是否被劫持?针对这两个

    2024年02月07日
    浏览(61)
  • 为什么网络可以ping通,还是不能ssh到目标主机?

      做运维工作,我们都是通过远程的方式去连接一台服务器或者虚拟机,很多初次做运维的朋友可能经常会遇到这样一个问题:我ping目标服务器的IP是通的,但是我通过ssh却不能连上主机。今天,就来浅谈一下,为什么你ping网络是通的,但是却不能连接到远程主机,当你弄

    2024年02月09日
    浏览(46)
  • 手机wifi可以连接路由器但是上不了网,为什么?

    本文转载自:路由器知识库:www.luyouqiset.cn 详细介绍无线路由器设置后却上不了网的解决办法。但我们拿到路由器后一般都是按照说明书,一步一步登陆后台去设置无线路由器。结果辛辛苦苦设置完后,发现手机,笔记本电脑都够连接到tplink路由器的网络但上不了网。气愤到先

    2024年02月11日
    浏览(77)
  • 为什么说云蜜罐可以让安全防御工作由被动变主动

    蜜罐技术本质上是一种对攻击方进行欺骗的技术,通过布置一些作为诱饵的主机、网络服务或者信息,诱使攻击方对它们实施攻击,从而可以对攻击行为进行捕获和分析,了解攻击方所使用的工具与方法,推测攻击意图和动机,能够让防御方清晰地了解他们所面对的安全威胁

    2024年04月10日
    浏览(35)
  • 0062__对象指针为NULL,为什么还是可以调用成员函数

    对象指针为NULL,为什么还是可以调用成员函数_空对象指针为什么能调用函数_一颗石头崽儿的博客-CSDN博客

    2024年02月10日
    浏览(37)
  • TCP实现原理和为什么需要三次握手?两次握手不可以?四次握手不可以?

    TCP实现原理和为什么需要三次握手?两次握手不可以?四次握手不可以? 1. 什么是TCP协议? TCP:Transmission Control Protocol翻译过来就是传输控制协议,TCP协议是一个面向连接的、可靠的、基于字节流的传输层协议 RFC 793对TCP连接的定义 Connections: The reliability and flow control mechanisms descri

    2024年02月16日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包