数据库07——锁

97 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

img

锁的作用与粒度

锁的作用管理对共享资源的并发访问保证事务的隔离性和一致性

封锁粒度的概念:MySQL中提供了两种封锁粒度,行级锁表级锁(基于页,锁一页而不是整个表)。

行级锁的封锁粒度小

  • 好处:锁定的数据量越少,发生锁竞争就越少,系统的并发程度就越高;
  • 坏处:系统开销大(加锁、 释放锁、检查锁的状态都需要消耗资源)

锁兼容性

排他锁、共享锁、意向锁、

  • 排它锁 X锁:加上X锁时,只允许此事务读取和修改此数据,并且其它事务不能加锁

  • 共享锁 S锁:加了S锁后,该事务只能对数据进行读取而不能修改,并且其它事务只能加S锁,不能加X

  • 意向锁(Intention Locks):IS、IX锁

    • 一个事务在获得某行数据S 锁之前,必须先获得整个表IS 锁
    • 一个事务在获得某行数据X 锁之前,必须先获得整个表IX 锁
    • 优点加快对整个表加锁的速度。如果一个事务想要对整个表加X锁,就需要先检测是否有其它事务对该表或者该表中的某一行加了锁,这种检测非常耗时。有了意向锁之后,只需要检测整个表是否存在IX/IS/X/S锁就行了
    • 意向锁和共享锁、排他锁的兼容关系。 意思是 当事务A对某个数据范围(行或表)上了“某锁”后,另一个事务B是否能在这个数据范围上“某锁”。

    updatedeleteinsert 都会自动给数据加上排他锁select 语句默认不会加任何锁

    那什么情况下会对读操作加锁呢?

    select … lock in share mode,对读取的记录加S锁 select … for update ,对读取的记录加X锁 在事务中读取记录,对读取的记录加S锁 事务隔离级别在 SERIALIZABLE 下,对读取的记录加S锁

在这里插入图片描述

加锁模式

记录锁、间隙锁、临键锁、插入意向锁、自增锁

记录锁(Record Locks) 行锁

  • 只对表中一行数据的索引加锁
  • 只能对唯一索引(主键索引)加锁,且查询语句必须为精确匹配 "=",否则产生临键锁
  • 指定查询某一条记录的加锁语句,如果记录存在,则只产生记录锁,否则产生临键锁。
  • 如果要锁的列没有索引,会在每一条聚集索引加记录锁,这个类似于表锁。(若没有任何索引,innodb会创建隐藏的聚集索引,锁住的就是隐藏的聚集主键索引。)

间隙锁(Gap Locks) 行锁 (1)区间锁在索引记录间的间隙中加锁锁住一个索引区间(开区间,不包括双端端点)

比如在 1、2、3中,间隙锁的可能值有 (∞, 1),(1, 2),(2, ∞), (2)间隙锁可保证索引间不被插入数据,防止幻读

(3)mysql每页有2个伪记录,使得间隙锁可以锁住第一条和最后一条记录

临键锁(Next-Key Locks) 行锁 (1)record lock + gap lock, 左开右闭区间innodb默认使用next-key locks来锁定记录。 (2)当查询的索引有唯一属性时,临键锁会变为记录锁。

MySQL加锁

 SELECT ... LOCK In SHARE MODE;
 SELECT ... FOR UPDATE;
 SELECT ... LOCK In SHARE MODE;
 SELECT ...  FOR UPDATE;

什么是乐观锁和悲观锁?

  • 悲观锁:认为数据随时会被修改,每次操作数据之前都会上锁,防止其它事务操作数据;适用于更新比较频繁的场景;
  • 乐观锁:不加锁而是假设没有冲突而去完成某项操作,如果存在冲突失败就重试,直到成功为止。适用于读多写少的场景。

CAS:乐观锁的一种实现,更新时会判断数据在此期间有没有别的事务更新,若被更新过,则失败重试;

CAS主要涉及三个值:当前内存值V、预期值(旧的内存值)O、将更新的内存值U,当且仅当预期值O与当前内存值V相等时,将内存值V批改为更新值U,返回true,否则返回false。

问题:1)ABA问题。2)自旋开销。3)无法处理多个共享变量

ABA问题的解决:CAS操作时,数据被修改了,又被改回去了,此事务认为数据没有被修改。

加一个版本号或者时间戳字段,每次数据更新时同时更新这个字段;(解决ABA问题)