行锁
意向锁(表锁)
一致性非锁定读
一致性锁定读
脏读
不可重复读
丢失更新(幻读)
latch:闩锁,轻量级,锁定时间短,性能高,目的是用来保证并发线程操作临界资源的正确性,通常没有死锁检测机制,分mutex(互斥量)和rwlock(读写锁)两种;
lock:与事务相关,用来锁定数据库中的对象:表、页、行,一般仅在commit和rollback后释放(不同事务隔离级别的释放时间可能不同),有死锁检测机制;
| lock | latch | |
| 对象 | 事务 | 线程 |
| 保护 | 数据库内容 | 内存数据结构 |
| 持续时间 | 整个事务过程 | 临界资源 |
| 模式 | 行锁、意向锁 | 读写锁、互斥量 |
| 死锁 | 通过waits-for graph、time out等机制进行死锁检测与处理 | 无死锁检测与处理机制,仅通过应用程序加锁的顺序保证无死锁的情况发生 |
| 存在于 | Lock Manager的哈希表中 | 每个数据结构的对象中 |
共享锁S Lock:允许事务读一行数据
排它锁X Lock:允许事务删除或更新一行数据
| X | S | |
| X | 不兼容 | 不兼容 |
| S | 不兼容 | 兼容 |
兼容是针对同一行数据而言的;
兼容性很好理解,因为只有读读是兼容的,而读写、写写都是不兼容的;
意向共享锁IS Lock:事务想要获取一张表中某几行的共享锁;
意向排它锁IX Lock:事务想要获取一张表中某几行的排它锁;
| IS | IX | S | X | |
| IS | 兼容 | 兼容 | 兼容 | 不兼容 |
| IX | 兼容 | 兼容 | 不兼容 | 不兼容 |
| S | 兼容 | 不兼容 | 兼容 | 不兼容 |
| X | 不兼容 | 不兼容 | 不兼容 | 不兼容 |

read committed:总是读取被锁定行最新一份快照数据,因为它是读已提交,而已提交就是最新的快照数据,但由于当前事务还未结束,故不满足隔离性;
repeatable read(Mysql默认隔离级别):总是读取事务开始时的行数据版本,所以它叫可重复读,满足隔离性;
select @@tx_isolation;
select @@global.tx_isolation;
SET session TRANSACTION ISOLATION LEVEL read committed;
SET global TRANSACTION ISOLATION LEVEL read committed;
select ... for update,X锁
select ... lock in share mode,S锁
脏页:缓冲池已经被修改的页,但是还没有刷新到磁盘,即数据库实例内存中的页与磁盘中的页是不一致的。脏页的刷新是异步的,不影响数据库的性能;
脏数据:指事务对缓冲池中行记录的修改,还没有被提交;
事务A开启事务,并修改了一行数据;
事务B开启事务,修改了同一行数据;
事务A提交;
事务B提交;
事务A开启事务,读取了一行数据,假设该行数据有一个age字段,且age=10;
事务B开启了事务,读取了同一行数据,即age=10。
事务A进行修改操作,使新age=原age+10,然后提交。
事务B进行修改操作,使新age=原age+20,注意原age,事务B使用的是自己一开始读取的10,而不是事务A提交后的20,因此修改后的age=30,然后提交;
将隔离级别设为序列化读;
对读取操作上排它锁,select ... for update;
record lock:记录锁,锁定本身;
grap lock:范围锁,锁定一个范围,不包含本身;
next-key lock:锁定范围+本身,设计的目的是为了解决幻读现象;
| 主键索引a | 辅助索引b |
| 1 | 1 |
| 2 | 1 |
| 5 | 3 |
| 7 | 6 |
| 10 | 8 |
1和6是开区间还是闭区间?
为什么where条件是b=3,我只锁住b=3就好了,为什么要锁住范围呢?假如我插入一条新数据(a=6,b=5),难道就会出现幻读吗?
将当前锁的粒度变粗。比如,数据库可以将表的1000个行级锁升级为一个页锁,防止系统使用太多的资源来维护锁,一定程度上提高了效率。




