MySQL – 锁和事务

微信扫一扫,分享到朋友圈

MySQL – 锁和事务

MySQL本身也是在文件系统的基础上发展而来,因为锁的存在使之有所不同。

MySQL
作为一种数据库软件,难免会存在对其 共享资源
并发访问
,为了 协调和管理
不同资源的并发访问,也就产生了 锁机制
,因为锁机制的存在为数据库提供了数据的 完整性
一致性

锁的级别
来分锁可分为:行级锁、表级锁、页级锁。

锁的类型
来分锁可分为:共享锁、排它锁(独占锁)。

为了协调 行锁、表锁
产生了:意向锁(表级锁)。

共享锁
,允许事务去 读取
数据。

排它锁
,允许事务去 修改或删除
数据。

意向锁
,获取行级锁的时候,自动添加的表级锁,包含:意向共享锁、意向排它锁。

对于 MyISAM
存储引擎,只支持 表锁
,而 InnoDB
存储引擎则支持 行锁、表锁

MyISAM
存储引擎修改、删除数据的时候,会产生排它锁,锁定的 整张表
,并发写入性能较差,而读取的时候产生的是共享锁,不会锁定表,读取性能就比较好。

InnoDB
存储引擎修改、删除数据的时候,会产生排它锁,锁定的 特定索引记录
,一般不会影响表中的其它行,并发写入性能较好,而读取的时候产生的是共享锁,不会锁定表和行,读取性能较好。

行锁锁定的是索引记录,而不是记录行,如果没有索引,则使用隐式索引进行锁定。

当一张表 某些行
已经获取了 排它锁
,在表中会产生一个 意向排它锁
,如果此时有一个事务要来锁定整张表,那么一看有 意向排它锁
的存在,该事务就会被 阻塞
,通过 意向锁
直接就可以知道能不能锁定表,不需要逐行去遍历检测是否有 排它锁
,通过意向锁高效地协调了行锁和表锁的关系。

行级锁
按照锁定范围来分,又分为三种:

Record Lock
Gap Lock
Next-Key Lock

当然,锁也是有利有弊的,也可能出现 死锁
的情况。

两个或两个以上
的事务在执行过程中,因 争夺资源
而造成一种 相互等待
的现象,称为 死锁

最后,也是因为锁的存在,丰富了后续事务的功能。

MySQL通过设计一种机制,使得数据能够完整地从一种一致性状态切换到另一种一致性状态,这种机制称为事务。

事务包含有四大特性:原子性(A)、一致性(C)、隔离性(I)、持久性(D),简称酸性。

原子性
:事务中的操作,要么全部成功,要么全部失败,不可切分。

一致性
:事务将数据库从一种一致性状态转变成另外一种一致性状态,并且保证数据的完整性。

隔离性
:又称并发控制,事务在提交之前对于其它事务是处于不可见的状态的。

持久性
:事务一旦提交,结果就是永久性的,不会因为数据库宕机而丢失数据。

原子性
持久性
是通过 redo
日志实现的, 一致性
是通过 undo
日志实现的, 隔离性
是通过 锁机制
实现的。

从本质上来说, 原子性
也是为了配合 持久性
而存在的,当事务的一部分写入 redo日志
后,发生了 崩溃、断电
,那么根据 原子性
来说,该次事务应当 恢复
,那么对于已经持久化到日志文件中的数据,就必须要通过 回溯
来撤销。在 InnoDB
存储引擎中, redo
重做日志对应的就是 ib_logfile0
ib_logfile1

接着,事务要进行 回滚
,那就需要通过 一致性
来保障,而 undo
日志就是用来实现 一致性
的,在 undo
日志中保存了多个版本的事务的一些信息,通过 undo
日志,将事务 rollback
到修改之前的样子。

在此,不得不提的是MySQL的 MVCC
多版本并发控制,它也是通过 undo
日志来实现的。

MVCC是通过在每一数据行后头添加2个隐藏字段 create version
delete version
以及每次开启一个事务会初始化一个 事务id
。新增一条数据的时候, create version
的值就等于 事务id
,删除数据的时候, delete version
就等于 事务id
,更新数据的时候会先删后增,在 undo
日志中就会存在2条数据,一条 delete version
就等于 事务id
,一条 create version
的值等于 事务id

在事务执行过程中,可能会同时存在其它的事务,而 多个
事务之前需要相互 隔离
,也就是要做到 并发控制
,锁就是用来实现 隔离性
的。MySQL的事务的 隔离级别
包含: Read Uncommitted
读未提交、 Read Committed
读已提交、 Read Repeatable
可重复读、 Serializable
串行化。其中, 读已提交
可重复读
是基于 MVCC
多版本并发控制来实现的。

锁,为事务的并发控制带来了好处,同时也带来了坏处,包括:脏读、不可重复读、幻读。

脏读
,指的是一个事务读到了另一个事务未提交的内容,一旦另一个事务回滚了,就出现了 脏数据

不可重复读
,指的是同一个事务使用同一句SQL进行 多次读取
,返回不同的结果。

幻读
,指的是一个事务在进行 增删
的时候,某些已经确定不会出现的记录突然出现。

要解决脏读,那就需要至少设置隔离级别为: Read Committed
读已提交。

要解决不可重复读,那就需要至少设置隔离级别为: Read Repeatable
可重复读。

要解决幻读,那就需要设置隔离级别为: Serializable
串行化或者采用 Next-Key Lock
间隙锁。

微信扫一扫,分享到朋友圈

MySQL – 锁和事务

如何通过 Spring 框架进行 JDBC 事务控制呢?

上一篇

马斯克等3人已再次被选为特斯拉董事 任期三年

下一篇

你也可能喜欢

MySQL – 锁和事务

长按储存图像,分享给朋友