:::info 事务业务中中一系列严密的操作,可能对于业务代码的一个方法或几个方法,对应数据库是一个或几个sql语句。 ::: 在mysql数据库的中事务中,有四大特性,原子性,一致性,持久性,隔离性。
隔离性:类似并发,多个事务,运行在相同的时间,执行相同的功能,为了保证每个事务都认为是自己一个事务在使用系统,避免造成脏读,幻读,可重复读的影响。MVCC和锁机制保证。
原子性:同时成功和同时失败。undo log保证
持久性:事务提交后,持久化到磁盘。redo log保证
一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

MVCC机制

MVCC在 Read Committed 和 Repeatable Read两个隔离级别下工作,不加读锁,配合写锁实现。
当前读(current read) :select … lock in share mode,select … for update,insert,update,delete 语句 也称锁定读(locking read),通过对读取到的数据(索引记录)加锁来保证数据一致性,当前读会对所有扫描到的索引记录进行加锁,无论该记录是否满足WHERE条件都会被加锁,读到的是最新的数据。
快照读(snapshot read):普通的 select 语句(不包括 select … lock in share mode, select … for update) MySQL使用MVCC (Multiversion Concurrency Control)机制来保证被读取到数据的一致性,读取数据时不需要对数据进行加锁,且快照读不会被其他事物阻塞。
MVCC = undo log + read view + 隐藏字段(事务id,回滚指针)
image.png
trx_id:每次对某条聚簇索引记录进行改动(增删改)时,都会把对应的事务id赋值给trx_id隐藏列。
roll_pointer:每次对某条聚簇索引记录进行改动(增删改)时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。
Undo log中存储的是老版本数据,当一个事务需要读取记录行时,如果当前记录行不可见,可以顺着undo log链找到满足其可见性条件的记录行版本。
Read View主要是用来做可见性判断的,比较事务id字段范围,展示那个数据可见。
image.png
MVCC 实现RR隔离级别,在事务开启后第一条查询select语句时产生read-view保持不变,可以保证可重复读,RC是每执行一次查询sql语句时生成read-view,可以保证读已提交。

锁机制

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。
实现方式:使用数据库中的锁机制
适用场景:写多读少(经常会产生冲突,乐观锁询问次数会效率低下)
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。
实现方式:一般会使用版本号机制(MVCC)或CAS算法实现。乐观锁是用于在应用层业务来实现的,在数据上添加版本号或时间戳,在业务提交时,判断版本号或时间戳是否是自己读取时的数据。
适用场景:读多写少(不会经常产生冲突,悲观锁并发程度会低下)
分类:
行锁:
共享锁:select…for share(8.0之前是 lock in share mode)
排它锁:select…for update
表锁:
用户设置的表锁:
表级共享锁:lock tables [表名] read
表级排他锁:lock tables [表名] write
意向锁【意向锁是InnoDB自动加的,不需用户干预】:减少了获取表级锁的判断,提高性能。
意向排它锁:获取排他行锁时必须先获取意向排他锁
意向共享锁:获取共享行锁时必须先获取意向共享锁
Innodb行锁的锁算法:InnoDB引擎通过给索引上的索引记录加锁的方式实现行级锁。
InnoDB引擎开启标准状态监控和锁监控
Set global innodb_status_output = ON;
Set global innodb_status_output_locks = ON;
使用show engine innodb status 查看详情
记录锁:针对索引记录的锁定【Select * from [表名] where id = 1 for update; #假设id = 1的记录存在】
间隙锁:锁定的是索引记录之间的间隙、仅针对RR级别的范围查询,锁住的是范围包括不存在的间隙,不能插入数据。
Next-key锁:记录锁+间隙锁,RR隔离级别下解决幻读的,锁住当前行的范围和下一行的范围。