读写并发的解决方案:
- 读使用MVCC, 写使用
- 读和写都使用锁。
读和写都使用锁进行解决
表级别的锁:
- 读写锁, S和X锁
- 间隙锁,防止幻读现象的发生
- 意向锁IS和IX,为了加表级锁节约时间。
行级别的锁:
- record-lock
- gap-lock
- next-key-lock
- insertAttentionLock
- 隐式锁:由于trx_id的存在,insert不会显式加索,如果其他事务需要加S或者X锁的时候,就会为这个事务生成一个锁,相当延迟加上一个锁
InnoDB锁的内存结构
- 锁所在的事务信息:指向事务的指针
- 索引信息:行级别的锁来说,需要记录属于哪个索引
- 表锁/行锁信息:
a. 行锁:space id, page Number, n_bits
b. 表锁:对哪个表进行加索 - type_mode:
a. lock_mode
b. lock_type: LOCK_TABLE/LOCK_REC
c. rec_lock_type: 普通的锁,间隙锁,记录间隙锁,意向锁,其他的类型 - 其他信息
- 一堆比特位 = (1 + (n_recs + LOCK_PAGE_BITMAP_MARGIN) / 8) * 8 = (1 + (n_recs + 64) / 8) * 8
a. heap_no
b. infimum
c. supremum
语句加锁分析
- 普通select语句
- 锁定读语句
- 半一致性读语句:如果不满足条件,就不对记录进行加锁了,直接跳过,读取下一条语句。
- insert 语句
a. 遇到重复的Key
b. 外键检查 - 总结:加锁情况,受到下面因素的影响
a. 事务的隔离级别
b. 语句执行时候的索引类型
c. 是否精确匹配
d. 是否是唯一性搜索
e. 具体执行语句类型
查看事务的加锁情况:
- select * from information_schema.INNODB_TRX\G
- show engine innodb status
死锁发现与分析
- 求助于错误日志:使用set global innodb_print_all_deadlocks = on;
- 求助于show engine innodb status: 有最近的死锁情况。
- 死锁的解决方法是让较小的事务进行回滚