Mysql技术内幕InnoDB存储引擎读书笔记--《六》锁

数据库系统区别于文件系统的一个关键特性,一方面要最大程度地利用数据库的并发访问,另外一方面还要确保每个用户能以一致的方式读取和修改数据。

锁的类型

InnoDB存储引擎实现了如下两种标准的行级锁:

  • 共享锁(S LOCK),允许事务读一行数据
  • 排它锁(X LOCK),允许事务删除或者更新一行数据

当一个事务已经获得了行r的共享锁,那么另外的事务可以立即获得行r的共享锁,因为读取并没有改变行r的数据,我们称这种情况为锁兼容。但如果有事务想获得行r的排它锁,则它必须等待事务释放行r上的共享锁——这种情况我们成为锁不兼容。

InnoDB存储引擎支持多粒度锁定,这种锁定允许在行级上的锁和表级上的锁同时存在。为了支持在不同粒度上进行加锁操作,InnoDB存储引擎支持一种额外的锁方式,我们称之为意向锁。意向锁是表级别的锁,其设计目的主要是为了在一个事务中揭示下一行将被请求的锁的类型。

  • 意向共享锁(IS Lock),事务想要获得一个表中某几行的共享锁。
  • 意向排它锁(IX Lock),事务想要获得一个表中某几行的排它锁。
    因为InnoDB支持的是行级别的锁,所以意向锁其实不会阻塞除全表扫以外的任何请求。

一致性的非锁定读操作

一致性的非锁定读操作(consistent nonlocking read)是指InnoDB存储引擎通过行多版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE、UPDATE操作,这时读取操作不会因此等待行上的锁释放,相反,存储引擎会去读取一个快照数据。

快照数据是指该行之前版本的数据,该实现是通过Undo段来实现。而Undo用来在事务中回滚数据,因而快照数据本身是没有额外的开销。此外,读取快照数据是不必要上锁的,因为没有必要对历史的数据进行修改。

这种并发控制,就是多版本并发控制。

在Read Comitted和Repeatable Read(InnoDB存储引擎的默认事务隔离级别)下,InnoDB存储引擎使用非锁定的一致性读。然后,对于快照数据的定义却不相同。在Read Comitted事务隔离级别下,对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据。在Repeatable事务隔离级别下和Repeatable Read事务隔离级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本。

所以,对于Read Commited的事务隔离级别而言,其实违反了事务的隔离性。

加锁方式

  • SELECT…FOR UPDATE 对读取的行记录加一个X锁。其他事务想在这些行上加任何锁都会被阻塞。
  • SELECT…LOCK IN SHARE MODE 对读取的行记录加一个S锁。其他事务可以向锁定的记录加S锁,但是对于家X锁,则会被阻塞。

自增长和锁

Mysql的auto_increment这个自增长计数器是加锁的,使用如下语句来得到计数器的值:
SELECT MAX(auto_inc_col) FROM t FOR UPDATE;
这个锁其实是采用一种特殊的表锁机制,为了提高插入的性能,锁不是再一个事务完成后才释放,而是在完成对自增长值插入的SQL语句后立即释放。

外键和锁

对于外键值得插入或者更新,首先需要查询父表中的记录,即SELECT父表,但是对于父表的SELECT操作,不是使用一致性非锁定读的方式,因为这样会发生数据不一致的问题,因此这时使用的是SELECT … LOCK IN SHARE MODE方式,主动对父表加一个S锁,如果这时父表上已经这样加X锁,那么子表上的操作会被阻塞。

锁和算法

InnoDB存储引擎有3种行锁的算法设计:

  • Record Lock:单个行记录上的范围
  • Gap Lock:间隙锁,锁定一个范围,但不包含记录本省
  • Next-Key Lock: Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身。

Record Lock总是会锁住索引记录,如果InnoDB存储引擎建立的时候没有设置任何一个索引,这时InnoDB存储引擎会使用隐式的主键来进行锁定。

比如:`SELECT * FROM t WHERE a < 6 lock in share mode,该语句会锁定(-oo, 6)这个数值区间的所有数值。

丢失更新

即多用户计算机系统下有可能产生的问题,用户同一个账号分别在不同机器上登录转账,如果不加锁,可能转账金额错误,必须通过加锁改为串行操作。

脏读

即一个事务可以读到另一个事务中未提交的数据,违反了数据库的隔离性。发生条件:READ UNCOMMITED,这个隔离级别在Mysql中不使用。

不可重复读

不可重复读是指在一个事务内多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该数据。有可能出现第一个事务两次读的数据不一样,即第二次读的数据受到另外一个事务的影响。

不可重复读和脏读的区别是:脏读是读到未提交的数据;而不可重复读读到的确实是已经提交的数据,但是其违反了数据库事务一致性的要求

InnoDB的默认事务隔离级别是READ REPEATABLE,采用Next-Key Lock算法,解决了不可重复读(幻读)问题。在Next-Lock Key 算法下,不仅仅是锁住扫描到的索引,而且还锁住这些索引覆盖的范围(gap)。因此对于这个范围内的插入都是不允许的。

死锁

InnoDB存储引擎并不会回滚大部分的错误异常,但是死锁除外。发生思索后,InnoDB存储引擎会马上回滚一个事务。(另一个事务就可以获取资源了)

锁升级

锁升级(Lock Escalation)是指将当前锁的粒度降低。比如1000个行锁升级为一个页锁,或者将页锁升级为表锁。

  • 由一句单独的SQL语句在一个对象上持有的锁的数量超过了阈值,默认的这个阈值为5000。值得注意的是,如果是不同对象的话,则不会发生锁升级。
  • 锁资源占用的内存超过了激活内存的40%时,就会发生锁升级。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值