当前位置:网站首页>行锁与隔离级别案例分析
行锁与隔离级别案例分析
2022-06-26 17:54:00 【 时光清浅ぴ许你安然】
更多内容,可前往深入理解MySQL锁与事务隔离级别查看
现有如下表:
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
一个session开启事务更新不提交,另一个session更新同一条记录会阻塞,更 新不同记录时不会阻塞。
1 读未提交
(1)打开一个客户端A,设置当前事务模式为read uncommitted(读未提交)并开启事务,查询初始化数据
①设置隔离级别并开启事务
set tx_isolation='read-uncommitted';

②查询表的初始数据
select * from account;

(2)在客户端A的事务提交之前,打开另一个客户端B,设置当前事务模式为read uncommitted(未提交读)并开始事务,更新表account:
①更新隔离级别为读未提交
set tx_isolation='read-uncommitted';

②查询初始化数据
③、更新数据
(3)这时,虽然客户端B的事务还没提交,但是客户端A就可以查询到B已经更新的数据:
(4)一旦客户端B的事务因为某种原因回滚,所有的操作都将会被撤销,那 客户端A查询到的数据其实就是脏数据:
(5)在客户端A执行更新语句update account set balance = balance - 50 where id =1,lilei的balance没有变成350,居然是400,是不是很奇怪,数据不 一致啊,如果你这么想就太天真 了,在应用程序中,我们会用400-50=350,并 不知道其他会话回滚了,要想解决这个问题可以采用读已提交的隔离级别
2 读已提交
(1)打开一个客户端A,设置当前事务模式为read committed(读已提交)并开启事务,查询初始化数据
①设置隔离级别并开启事务
set tx_isolation='read-committed';

②查询表的初始数据
select * from account;

(2)在客户端A的事务提交之前,打开另一个客户端B,设置当前事务模式为read committed(读已提交)并开始事务,更新表account:
①更新隔离级别为读已提交
set tx_isolation='read-committed';

②查询初始化数据
③、更新数据
(3)这时,客户端B的事务还没提交,客户端A不能查询到B已经更新的数 据,解决了脏读问题:
(4)客户端B的事务提交
(5)客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题(同一事务中执行同一SQL返回不同的结果)
3 可重复读
(1)打开一个客户端A,设置当前事务模式为repeatable read(可重复读)并开启事务,查询初始化数据
①设置隔离级别并开启事务
set tx_isolation='repeatable-read';

②查询表的初始数据
select * from account;

(2)在客户端A的事务提交之前,打开另一个客户端B,设置当前事务模式为repeatable read(可重复读)并开始事务,更新表account:
①更新隔离级别为可重复读
set tx_isolation='repeatable-read';

②查询初始化数据
③、更新数据
(3)这时,提交客户端B的事务,查看客户端A的数据

(4)在客户端A,接着执行update account set balance = balance - 50 where id = 1,balance没有变成400-50=350。
lilei的balance值用的是sessionB中的350来算的,所以是300,数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC(multi-version concurrency control)机(多版本并发控制机制)。
select操作不会更新版本号,是快照读(历史版本);
insert、update和delete会更新版本号,是当前读(当前版本)。
(5)客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题(同一事务中执行同一SQL返回不同的结果)
关于MVCC机制,具体看前往MySQL的MVCC机制详解进行查看
4 幻读
(1)打开一个客户端A,开启事务,查询初始化数据
(2)手动在数据库中插入一条记录,然后再去客户端A查询数据

发现查询出的数据还是第一次查询的三条数据。
(3)更新上一步手动插入的数据
发现更新成功了。
(4)再次查询数据
发现数据确实已被更新,且也可以查询出来了。
这种情况就是幻读,很魔幻的感觉,更新了,就多了一条数据了。
幻读的情况,可设置事务隔离级别为串行化可解决(但是效率低下,几乎不会使用,这里不进行介绍)。
问:Mysql默认级别是repeatable-read,有办法解决幻读问题吗?
答:间隙锁在某些情况下可以解决幻读问题
比如:现在有如下数据
可以看到,id中4和10之间有个间隙、10和20之间是有间隙的(之间还可以插入一些11、12…等数据,还有一些空白的id没有被使用到)
开启事务
查询数据
更新数据
只要事务不提交,那么id 4~10、10 ~ 20之间的间隙就会被加锁。
我们可以手动在数据库里插入数据来验证
直到我们回滚或者提交事务会后,上述阻塞的地方就会正常
以此看来,间隙锁是可以帮助我们处理幻读的问题。
一旦开启间隙锁,则加锁的部分不再允许插入(未加锁的部分依然可以正常插入),那么session中查询的数据永远都是之前的记录
无索引行锁会升级为表锁:锁主要是加在索引上,如果对非索引字 段更新, 行锁可能会变表锁
InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为表锁。
锁定某一行还可以用lock in share mode(共享锁) 和for update(排它锁),
例如:select * from test_innodb_lock where a = 2 for update;
这样其他session只能读这行数据,修改则会被阻塞,直到锁定行的session 提交
5 结论
Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的 性能损耗可能比表级锁定会要更高一下,但是在整体并发处理能力方面要远远优 于MYISAM的表级锁定的。当系统并发量高的时候,Innodb的整体性能和 MYISAM相比就会有比较明显的优势了。
Innodb但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候, 可能会让Innodb的整体性能表现不仅不能比MYISAM高,甚至可能会更差。
6 优化建议
(1)尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
(2)合理设计索引,尽量缩小锁的范围 尽可能减少检索条件范围,避免间隙锁
(3) 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql 尽量放在事务最后执行
(4)尽可能低级别事务隔离
边栏推荐
- 正则匹配相同字符
- 接水面试题
- Applet setting button sharing function
- RSA概念详解及工具推荐大全 - lmn
- The high concurrency system is easy to play, and Alibaba's new 100 million level concurrent design quick notes are really fragrant
- 如何将应用加入到deviceidle 白名单?
- [buuctf.reverse] 126-130
- 我想知道,我在肇庆,到哪里开户比较好?网上开户是否安全么?
- 数据加密标准(DES)概念及工作原理
- 在国金证券开户怎么样?保障安全吗?
猜你喜欢

Treasure and niche CTA animation material website sharing

transforms.RandomCrop()的输入只能是PIL image 不能是tensor

【万字总结】以终为始,详细分析高考志愿该怎么填

Leetcode - 226. Retourner l'arbre binaire (bfs)

RuntimeError: CUDA error: out of memory自己的解决方法(情况比较特殊估计对大部分人不适用)

数字签名论述及生成与优点分析

Strength and appearance Coexist -- an exclusive interview with Liu Yu, a member of Apache pulsar PMC

Microservice architecture practice: user login and account switching design, order query design of the mall
![[ten thousand words summary] starting from the end, analyze in detail how to fill in the college entrance examination volunteers](/img/77/715454c8203d722e246ed70e1fe0d8.png)
[ten thousand words summary] starting from the end, analyze in detail how to fill in the college entrance examination volunteers

物联网协议的王者:MQTT
随机推荐
Detailed explanation of browser storage methods: the origin and difference of cookies, localstorage and sessionstorage
The difference between round and truncate in SQL (round or truncate)
并发之Synchronized说明
The high concurrency system is easy to play, and Alibaba's new 100 million level concurrent design quick notes are really fragrant
在国金证券开户怎么样?开户安全吗?
Quantitative contract system development analysis case - detailed explanation of contract quantitative system development scheme
正则匹配相同字符
Applet setting button sharing function
Use middleware to record slow laravel requests
Number of solutions for knapsack problem
Vscode usage - Remote SSH configuration description
Detailed explanation of dos and attack methods
Play with Linux and easily install and configure MySQL
背包问题求方案数
pycharm的plt.show()如何保持不关闭
pycharm如何修改多行注释快捷键
[ten thousand words summary] starting from the end, analyze in detail how to fill in the college entrance examination volunteers
牛客网:设计LRU缓存结构 设计LFU缓存结构
KDD 2022 | how to use comparative learning in cross domain recommendation?
Digital signature standard (DSS)