mysql-锁

当一个事务对记录进行update的时候会先去内存查看是否有一个锁结构跟这条记录关联,如果没有就创建一个锁结构与记录关联保存着trx_id和is_waiting = false

在事务未提交期间,又一个事务要更新这条记录,查到有锁结构与记录关联,会新创建一条锁结构,保存的is_waiting = true表示获取锁失败

 在sql标准定义下,repeatable read隔离级别会解决脏读/不可重复读问题,不能解决幻读

但是mysql在repeatable read隔离级别 实际上就已经解决了幻读

方案一:

  读操作使用多版本并发控制,写操作进行加锁 

  再唠叨一句,read committed级别每次查询 创建一个readview repeatable read 在同一事物中 第一次查询才创建readview

方案二:

  读写都加锁

一致性读

  在read committed/repeatable read隔离级别下,事物使用mvcc进行读取的都称为一致性读

锁定读

  共享锁/独占锁

  共享锁, 当有记录被加上共享锁 读事务可以加 共享锁读,加独占锁写的时候需要等待共享锁释放

  独占锁, 当有记录被加上独占锁,其他事务加共享锁或者独占锁都需要等待记录的独占锁被释放

  显示的为读语句加锁:

  共享锁 select ....lock in share mode

  独占锁 select ....for update

锁定写

  delete 先给记录加锁 然后delete_mark

  update

    不更新主键,并且占用空间不发生变化,先获取独占锁,然后更新

    不更新主键,占用空间变化,先获取独占锁,然后完全删除记录 在insert新记录insert操作由隐式锁保护

    更新主键, 就是普通的delete操作+insert操作

  insert 使用隐式锁保护在事务提交前不被其他事务访问

 粗粒度锁 表级锁 也有共享锁和独占锁

 意向锁 is/ix 相当于对表锁的表级 目的是在对表加表级锁s/x时,表名表中有记录使用了s/x锁 不用遍历查看

以上都是sql定义的锁

下面来分析一下mysql定义的锁

 innodb引擎下的锁 支持表锁和行锁

 表级别的s/x锁

 innodb提供的表级锁只会在一些特殊的阶段会被使用到,比如崩溃恢复

 表级别的is/ix锁

 当对记录加s锁(行锁)前会先在表上加is锁,在对记录加x锁(行锁)前会先在表上家ix锁,为表加s/x锁是,表明表中有记录使用了s/x锁 不用遍历查看

 表级别的auto-inc锁

 当主键被修饰自增,在添加数据的时候使用

  1. auto-inc锁

    auto-inc锁 只针对单个插入语句执行完就释放锁,不针对整个事务

  2. 轻量级锁

    分配完自增的id后就释放轻量级锁,而不是插入语句执行完,这个针对知道具体的插入记录数时

innodb中的行级锁

  record locks:

  分共享和独占锁,特性跟以上一样

  gap locks:

  间隙锁,当给记录加了gap locks 在记录前面是不可以插入记录的直到释放了gap locks

  repeatable read隔离级别下,事务中第一次读取查出了记录,第二次查询之前有新数据加入,所以我们无法给这些幻影记录加锁,所以就出现了间隙锁

  gap锁只是为了防止幻读不起其他的作用

  next key locks:

  是recode locaks和gap locks的组合

  insert intention locks:

  当有事务想向加了gap locks锁的记录前插入一条记录时,这个事务会在内存生成一个insert intention locks锁,只作为记录没实际意义

   隐式锁:

  当一个事务首先插入了一条记录,然后另一个事务立即使用select..lock in share mode/for update 获取S/X锁 

  - 针对聚簇索引 这时后面这个事务会查看这条记录项的trx_id属性,如果这个trx_id对应的事务在活跃状态,后面事务会为前面事务添加锁记录,自己添加锁记录并等待

  - 对于二级索引来说 后面事务根据二级索引页PAGE_MAX_TRX_ID属性小于当前活跃事务的最小值的话说明对该页面做修改的事务已经提交,否则先找到对应的记录根据

   二级索引,然后回表重复第一步就行

  一个事务对新插入的记录可以不显示的加锁(生成一个锁记录),根据事务id的大小,别的事务在对这条记录加S/X锁时,会先帮前一个事务生成一个锁结构,

  然后自己再生成一个锁结构后进入等待状态

innodb锁的内存结果

  在一些条件下,锁结构是可以复用的

  1. 在同一个事务中

  2. 被锁记录在同一个页面

  3. 加锁类型一样

  4. 加锁等待状态一样

锁结构

  

- 锁所在的事务信息

  代表由那个事务创建的这个锁记录

索引信息

  记录一下加锁的记录是属于哪个索引的

表锁/行锁的信息

    表锁

      1. 记录着对哪个表加锁的信息

    行锁

      1. space id 所在表空间

      2. page number 记录所在页号

      3. n_bits 代表使用了多少byte位

      4. type_mode 32位的数分成了lock_mode lock_type rec_lock_type

        - lock_mode锁的模式

          1. lock_is

          2. lock_ix

          3. lock_s

          4. lock_x

          5. lock_auto_inc

         - lock_type 锁的类型

          1. lock_table 表级锁

          2. lock_rec 行级锁

        - rec_lock_type 行锁的具体类型

          1. lock_ordinary 表示next-key锁 及锁住这条记录 又阻止在这条记录的间隙添加数据

          2. lock_gap 间隙锁

          3. lock_rec_not_gap 正经记录锁

          4. lock_insert_intention 插入意向锁

        当第9个比特位位置为1代表is_waiting为true 为0代表if_waiting为false

- 一堆比特位

  如果是行锁记录,一个比特位对应着一个记录头信息中的heap_no

  在一个事务需要为多条记录加锁的时候,如果一个记录发生阻塞 后面的记录就不会进行加锁

原文地址:https://www.cnblogs.com/isnotnull/p/14516195.html