- 读写锁
- 一致性快照读,即 MVCC
读未提交(Read Uncommitted)官方说法:
SELECT statements are performed in a nonlocking fashion, but a possible earlier version of a row might be used. Thus, using this isolation level, such reads are not consistent.读未提交,采取的是读不加锁原理 。
- 事务读不加锁,不阻塞其他事务的读和写
- 事务写阻塞其他事务写,但不阻塞其他事务读;
InnoDB implicitly converts all plain SELECT statements to SELECT ... FOR SHARE if autocommit is disabled. If autocommit is enabled, the SELECT is its own transaction. It therefore is known to be read only and can be serialized if performed as a consistent (nonlocking) read and need not block for other transactions. (To force a plain SELECT to block if other transactions have modified the selected rows, disable autocommit.)
- 所有SELECT语句会隐式转化为SELECT ... FOR SHARE,即加共享锁 。
- 读加共享锁,写加排他锁,读写互斥 。如果有未提交的事务正在修改某些行,所有select这些行的语句都会阻塞 。
隐式字段对于InnoDB存储引擎,每一行记录都有两个隐藏列DB_TRX_ID、DB_ROLL_PTR,如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列DB_ROW_ID 。
- DB_TRX_ID,记录每一行最近一次修改(修改/更新)它的事务ID,大小为6字节;
- DB_ROLL_PTR,这个隐藏列就相当于一个指针,指向回滚段的undo日志,大小为7字节;
- DB_ROW_ID,单调递增的行ID,大小为6字节;
文章插图
undo日志
事务未提交的时候,修改数据的镜像(修改前的旧版本),存到undo日志里 。以便事务回滚时,恢复旧版本数据,撤销未提交事务数据对数据库的影响 。undo日志是逻辑日志 。可以这样认为,当delete一条记录时,undo log中会记录一条对应的insert记录,当update一条记录时,它记录一条对应相反的update记录 。存储undo日志的地方,就是回滚段 。多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(DB_ROLL_PTR)连一条Undo日志链 。
我们通过例子来看一下~
mysql> select * from account ;+----+------+---------+| id | name | balance |+----+------+---------+|1 | Jay|100 |+----+------+---------+1 row in set (0.00 sec)复制代码
- 假设表accout现在只有一条记录,插入该该记录的事务Id为100
- 如果事务B(事务Id为200),对id=1的该行记录进行更新,把balance值修改为90
文章插图
快照读&当前读快照读:
读取的是记录数据的可见版本(有旧的版本),不加锁,普通的select语句都是快照读,如:
select * from account where id>2;复制代码
当前读:读取的是记录数据的最新版本,显示加锁的都是当前读
select * from account where id>2 lock in share mode;select * fromaccount where id>2 for update;复制代码
Read View- Read View就是事务执行快照读时,产生的读视图 。
- 事务执行快照读时,会生成数据库系统当前的一个快照,记录当前系统中还有哪些活跃的读写事务,把它们放到一个列表里 。
- Read View主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据~
m_ids:当前系统中那些活跃的读写事务ID,它数据结构为一个List 。min_limit_id:m_ids事务列表中,最小的事务ID max_limit_id:m_ids事务列表中,最大的事务ID
- 如果DB_TRX_ID < min_limit_id,表明生成该版本的事务在生成ReadView前已经提交(因为事务ID是递增的),所以该版本可以被当前事务访问 。
- 如果DB_TRX_ID > m_ids列表中最大的事务id,表明生成该版本的事务在生成ReadView后才生成,所以该版本不可以被当前事务访问 。
推荐阅读
- 荨麻疹能彻底治好吗
- 一通百通,一文实现灵活的 K8S 基础架构
- 一文带你了解搜索功能设计
- 翡翠|一文读懂翡翠的种
- 彻底弄透Java处理GMT/UTC日期时间
- 微软|诞生25年后:Windows彻底告别SMB1传输协议
- 一文看懂 HashMap 中的红黑树实现原理
- 一文看懂HMS Core到底是什么
- 通过实验读懂神经网络识别VPN行为
- 建议收藏 一文深度讲解JVM 内存分析工具 MAT及实践