MySQL--事务与锁

事务


定义

事务是数据库管理系统(DBMS)执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。(维基百科)

MySQL只有InnoDB存储引擎支持事务

事务的开启和关闭
数据库默认是自动事务开启的,执行任意的增删改都会自动开启事务。
也可以手动开启事务:

-- 设定事务是否自动开启
set session autocommit = on/off;
-- 手工方式开启
begin / start transaction      
-- 结束事务:提交或回滚
commit / rollback

事务的四大特性(ACID)

原子性(Atomicity)

是指事务中对数据库的一系列操作,要么都是成功,要么都是失败。

在InnoDB里面是通过undo log来实现的, 它记录了数据修改之前的值 (逻辑日志),一旦发生异常,就可以用undo log来实现回滚操作。

一致性(Consistency)

指的是数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态。

隔离性(Isolation)

隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。

持久性(durability)

事务提交成功,事务中所有的数据操作都必须是永久性的,被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。

持久性是通过redo log和双写缓冲机制(double write buffer)保证的。

事务并发的问题

脏读

事务里面,一个事务查询的数据,因为其他事务修改了数据且并没有提交,导致前后两次读取情况不一致。

重复读

事务里面,一个事务查询的数据,因为其他事务修改/删除了数据并且提交了,导致前后两次读取情况不一致。

幻读

事务里面,一个事务查询的数据,因为其他事务插入了数据并且提交了,导致前后两次读取情况不一致。

image

事务的隔离级别

读未提交 (Read Uncommitted)

一个事务可以读取到其他事务未提交的数据,会出现脏读。叫做RU,没有解决任何的问题。

读已提交 (Read Committed)

一个事务只能读取到其他事务已提交的数据,不能读取到其他事务未提交的数据,解决了脏读的问题。

可重复读 (Repeatable Read)

同一个事务里面多次读取同样的数据结果是一样的,对读取的数据快照或者加锁,解决了重复读,但不能解决幻读。

串行化 (Serializable)

所有的事务都是串行执行的,对数据的操作需要排队,不存在事务的并发操作了,所以解决了所有的问题。
image

并发控制实现

LBCC

Lock Based Concurrency Control(基于锁的并发控制):在读取数据前,对其加锁,阻止其他事务对数据进行修改。

MVCC

Multi Version Concurrency Control(多版本的并发控制):生成一个数据请求时间点的一致性数据快照(Snapshot),并用这个快照来提供一定级别(语句级或事务级)的一致性读取。

核心思想:查询当前事务之前提交的已存在的数据,即使后面被其他事务修改或者删除了,当前事务查到的还是之前的数据。后面其他事务新增的数据,当前事务是看不到的。

InnoDB为每行记录都实现了三个隐藏字段

  • ROWID:6字节,行标识。(主键索引有介绍)
  • DB_TRX_ID:6字节,插入或更新行的最后一个事务的事务ID,自增的(创建版本号
  • DB_ROLL_PTR:7字节,回滚指针,数据被删除或记录为旧数据的时候,记录当前事务ID(删除版本号
MVCC的版本控制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h6yKOGS8-1590046122654)(http://assets.processon.com/chart_image/5ebcf2d17d9c08156c3febd0.png)]
MVCC的查找规则:只能查找创建时间小于等于当前事务ID的数据,和删除时间大于当前事务ID的行(或未删除)。

  1. 事务1 初始化插入了两条user数据,此时创建版本是当前事务ID,删除版本为空。
  2. 事务2 查询出来两条user数据。
  3. 事务3 插入一条新数据,新数据创建版本是3,删除版本为空
  4. 事务2 查询user表,根据规则,只能查到创建版本小于1的两条数据
  5. 事务4 删除user表第二条数据,该数据删除版本为4
  6. 事务2 查询user表,根据规则,删除版本4大于事务id2,可以被查出来。可以显示两条数据
  7. 事务5 更新user表第一条数据,原数据删除版本为5,新增一条创建版本为5的版本数据,删除版本为空
  8. 事务2 查询user表,根据规则,创建版本5大于事务id2,不展示,删除版本5大于当前事务版本2可展示,所以展示原来的两条数据。

通过版本号的控制,无论其他事务是插入、修改、删除,第一个事务查询到的数据都没有变化。

InnoDB锁机制


表锁、行锁

表锁(Table Lock)

  • 表级锁一次会将整个表锁定,颗粒度大。
  • 加锁效率高:获取锁和释放锁的速度快。
  • 锁冲突概率高,避免死锁
  • 并发性能差

行锁(Record Lock)

  • 记录锁,加锁的是数据行,锁颗粒度小
  • 加锁效率略低,加锁逻辑复杂
  • 锁冲突概率小,会出现死锁
  • 并发性能高

行锁表锁对比

锁定粒度: 表锁 > 行锁
加锁效率: 表锁 > 行锁
冲突概率: 表锁 > 行锁
并发性能: 表锁 < 行锁

行锁:共享锁、排他锁

共享锁(Shared Locks)

定义

共享锁,又称为读锁,简称S锁。
共享锁就是多个事务可以共享一把锁,都能访问到数据,但是能读不能修改。

加锁

select * from user where id=1 LOCK IN SHARE MODE;

释放锁

事务结束

排他锁(Exclusive Locks)

定义

排他锁,又称为写锁,简称X锁。
排他锁不能与其他锁并存,一个事务获取数据行的排他锁,其他事务就不能再获取该数据的锁(共享锁、排他锁),只有该获取了排他锁的事务可以对数据行进行读取和修改。

加锁

自动:delete / update / insert 默认加上X锁;
手动:select * from student where id=1 FOR UPDATE;

释放锁

事务结束

InnoDB行锁实现

核心:行锁锁的是索引
InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,才使用行级锁;在不通过索引条件查询的时候,将使用表锁。

意向锁(Intention Lock)(表级)

意向锁是由数据引擎自己维护的,用户无法手动操作意向锁 。

意向共享锁(Intention Shared Lock,简称IS锁)

表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁。

意向排他锁(Intention Exclusive Lock,简称IX锁)

表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。

意向锁作用

表级和行级锁共存时,意向锁相当于一个表flag。
当该表被事务A加了行锁,事务B又准备加表锁,应该是阻塞的。这时候如果遍历所有行判断是否有锁,效率低。直接判断是否有意向锁就能给出结果,效率高。

行锁算法

记录锁(Record Lock)

记录(Record)

image
索引中存在的主键值,叫做Record。

单个行记录上的锁,通过索引使用等值查询,精准匹配到一条记录的时候,这个时候使用的就是记录锁。

例:

-- 锁住id 为2
select * from user where id = 2 for update;

间隙锁(Gap Lock)

间隙(Gap)

image
存在的Record隔开的数据,不存在的区间,叫做间隙(Gap),是一个左开右开的区间

查询的记录不存在,没有命中任何一个record,无论是用等值查询还是范围查询的时候,此时使用的是间隙锁。
不会阻塞相同的间隙锁,但是会阻塞插入间隙锁,这也是用来防止幻读的关键
间隙锁,只在RR隔离级别下存在。

例:

-- 返回查询
select * from user where id >4 and id <7 for update;
-- 等值查询没命中
select * from user where id = 6 for update;

-- 阻塞插入 block
insert user id(5) 

锁定了间隙区间,阻塞插入。

临键锁(Next-key Lock)

临键(Next-key)

image
间隙(Gap)连同右边的记录(Record),我们把它叫做临键的区间,是一个左开右闭的区间。

使用范围查询时,命中Record记录,还包含Gap间隙,就使用临键锁
是MySQL里面默认的行锁算法,相当于记录锁加上间隙锁。
临键锁,锁住最后一个key的下一个左开右闭的区间。

例:

-- 锁住(4,7]和(7,10]
select * from t2 where id >5 and id <=7 for update; 
-- 锁住(7,10],(10,+∞)
select * from t2 where id >8 and id <=10 for update; 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章