什么是锁
MyISAM中使用表锁
InnoDB使用行锁
InnoDB存储引擎中的锁
- 两种标准的行级锁:
共享锁(S),允许事务读数据
排他锁(X),允许事务删除/更新数据
- 意向锁:
下一行将被请求的锁的类型
意向共享锁;意向排他锁
意向锁只会阻塞全表扫的请求
通过INFORMATION_SCHEMA架构下的INNODB_TRX, INNODB_LOCKS, INNODB_LOCK_WAITS可以查看当前事务以及锁信息
- 一致性非锁定读(默认):
通过行多版本控制的方式读取数据
如果读取的数据上了X锁,则读取行的一个快照版本
快照数据通过Undo来实现
READ COMMITTED:使用最新的快照数据
REPEATABLE READ:使用事务开始时的数据
- 对读取数据枷锁:
SELECT … FOR UPDATE:加X锁
SELECT … LOCK IN SHARE MODE:加S锁
- 自增长和锁:
自增长计数器
自增长值得列必须是索引得第一个列
AUTO-INC Locking:插入使自增长计数器值加1赋予自增长列
锁在完成对自增长值插入的SQL语句后释放
提供轻量级互斥量的自增长实现机制,提高自增长值插入性能(互斥量mutex)
- 外键列:
自动添加索引,避免表锁
对父表读取,采用S锁
锁算法
Record Lock:单行记录上的锁(锁住索引记录)
Gap Lock:锁定一个范围,但不包含记录本身
Next-Ket Lock:锁定一个范围,并且锁定记录本身
锁问题
1.丢失更新
T1查询数据
T2也查询该数据
User1修改记录更新数据库并提交
User2也修改记录并提交
User1的更新操作丢失
解决方式:对记录加上X锁
2.脏读
读取到未提交的数据
大部分数据库至少为READ COMMITTED
InnoDB默认的事务隔离级别为READ REPEATABLE
3.不可重复读(Phantom Problem)
同一个事务内多次读同一个数据值不同(由于另一个事务提交了数据)
解决方式:Next-Key Lock
阻塞
使用Mutex数据结构实现锁
使用mutex_enter申请资源;mutex_exit释放资源
可以设置等待超时是否对进行中的事务进行回滚(默认不回滚)
死锁
发现死锁后,立马回滚一个事务
Oracle常见死锁原因:没有对外键添加索引
锁升级
将当前锁的粒度降低
把一个表的1000个行锁升级为页锁/页锁升级为表锁
防止使用太多内存维护锁
- 锁升级的情况:
1.一个对象持有的锁数量超过阈值
2.锁资源占用的内存超过阈值