InnoDB锁

  • 默认是行锁(row lock)
  • InnoDB是通过在索引记录上加锁,实现行锁
  • 因此没有索引时就无法实现行锁,从而升级成全表记录锁,等同于表锁。
  • 索引效率很低时锁也会升级。需要加锁的数据量过多,也会直接升级锁范围。 因为这样代价会低很多。

如同用书占座,只有当其他人想坐过来的时候,帮占座的人才会出面提出该座位已经被占用(被锁)

InnoDB行锁实现机制

  • 基于索引实现,逐行检查,逐行加锁
  • 没有索引的列上需要加锁时,会先对所有记录加锁,再根据实际情况决定是否释放锁。
  • 辅助索引上加锁时,同时要回溯到主键索引上再加一次锁。
  • 加锁的基本单位默认时lock_ordinary,当索引就具有唯一性的时候退化为lock_rec_not_gap
  • 等值条件逐行加锁时,会向右遍历到第一个不满足条件的记录,然后lock_ordinary退化为lock_gap
  • 如果发生唯一性检测(insert\update动作),那么会发生lock_ordinary , 再退化成lock_rec_not_gap
  • 唯一索引的范围条件加锁时,也会对第一个不满足条件的记录加锁

InnoDB隐式、显式锁

  • 显式锁(explicit-lock)

    • select .. from .. where .. for update / for share
  • 隐式锁(implicit-lock)
    • update set .. where ..
    • 任何辅助索引上锁,或非索引列上锁,都要回溯到主键上再加锁。
    • 和其他session有冲突时,隐式锁转换为显式锁。

InnoDB锁类型

共享锁

select .. for share/ lock in share mode

  • 不允许其他事务修改被锁定的行,只能读
  • 自动提交模式下的普通select是一致性非锁定读,不加锁。

排他锁

  • 对一行记录DML时,至少加上排他锁
  • 锁范围视情况而定,可能是record lock、next-key lock、或者可能只有 gap lock
  • 执行DML,或select.. for update

意向锁

  • InnoDB特有,加载在表级别上的锁。
  • Intention shared(IS),事务想要获得表中某几行的共享锁
  • Intention exclusive(IX), 事务想要获得表中某几行的排他锁
  • 意向锁时加载在数据表B+树结构的根节点,也就是对整个表加意向锁
  • 意向锁的作用,避免在执行DML时,对表执行DDL操作导致数据不一致
  • IS和IX 是可以兼容的。

InnoDB锁兼容性

X IX S IS AutoInc
X × × × × ×
IX × ×
S × × ×
IS ×
AutoInc × × ×

InnoDB行锁范围、粒度

InnoDB对行锁有进一步的细粒度:

  • LOCK_REC_NOT_GAP,record lock without gap lock.
  • LOCK_GAP,gap lock
  • LOCK_ORDINARY,next-key lock = record lock + gap lock ,普通辅助索引RR级别的加锁范围。
  • LOCK_INSERT_INTENTION

InnoDB行锁粒度一览

lock wait 表示等待锁。

lock_ordinary next-key lock,普通锁,LOCK_S record lock + gap lock ,next-key lock 锁定记录本身和前面的gap,record lock + gap lock (也叫next-key lock) RR级别下,利用next-key lock来避免产生幻读 当innodb_locks_unsafe_for_binlog=1时,lock_ordinary会降级为lock_rec_not_gap,相当于降级到RC。 8.0版本取消了参数innodb_locks_unsafe_for_binlog,即不再允许RR级别的幻读情景。
lock_gap gap lock 锁定一个范围,但不包含记录本身。 只锁住索引记录之间、或第一条索引记录(INFIMUM)之前、又或最后一条索引记录(SUPEREMUM)之后的范围,并不锁住记录本身 RR级别下,对非唯一索引记录当前读时,除了对命中的记录加lock_ordinary锁,还会对该记录之后的gap加gap lock,这是为了保证可重复读的需要,避免其他事务插入数据造成幻读。 innodb有两条虚拟记录,最小记录和最大记录,用来构建B+tree。 如果条件是where <= n, 这时会从n开始到最小值(虚拟最小记录)之间范围加锁 如果条件是where >= n, 这时会从n开始到最大值(虚拟最小记录)之间范围加锁
lock_rec_not_gap record lock,锁定记录,但不锁gap。 record lock,单个记录上的锁。 仅锁住记录本身,不锁前面的gap RC下的行锁大多数都是这个锁类型 RR下的主键、唯一索引等值条件下加锁也通常是这个类型锁 RR下的非唯一索引加锁时(lock_ordinary),也会同时回溯到主键上加lock_rec_not_gap锁。 但唯一性约束检测时,即使是在RC下,总是要先加lock_s\lock_ordinary锁。
lock_insert_intention 意向插入锁 是一种特殊的gap lock。 当插入索引记录的时候用来判断是否有其他事务的范围锁冲突,如果有就需要等待。 同一个GAP中,只要不是同一个位置就可以有多个插入意向锁并存。 例如5~10区间,同时插入6、8就不会相互冲突阻塞,而同时插入9就会引发冲突阻塞等待。 插入意向锁和间隙锁(gap lock)并不兼容,一个gap加了lock gap后,无法再加insert_intention。

lock_conv_by_other 锁时由其他事务创建的(比如隐式锁转换)

意向插入锁的示意:

操作InnoDB表时的加锁等级

  • RR级别以及等值条件加锁时:

    • 主键索引等值条件加锁为lock_rec_not_gap
    • 唯一辅助索引等值条件加锁为lock_rec_not_gap
    • 普通辅助索引等值条件加锁为lock_ordinary
    • 没有索引的话加锁为全表范围lock_ordinary
  • RC级别以及5.7及以前版本 RR& innodb_locks_unsafe_for_binlog =1 时
    • 默认只有lock_rec_not_gap,只有在检查外键约束或者duplicate ey检查时才加lock_orainary | lock_s

MyISAM引擎有表锁,InnoDB引擎也可以加表锁。

InnoDB自增锁 auto-inc lock

binlog_format=row时,可以放心的设置innodb_autoinc_lock_mode=2,降低自增锁的影响。

5.1之后新增innodb_autoinc_lock_mode选项。5.1以前,所有自增锁都是表级别锁,5.1以后可以有不同的选项。

同样的,也是在5.1以后binlog format支持多种方式(row,statement,mixed)。

  • 传统模式(模式为0):

    • 对单表上的并发影响极大
    • 当任何一条SQL要插入新数据, 都要求发起一个表级别自增锁,请求得到最新的自增ID , sql执行完成后,表级别自增锁释放。
    • 如果是多条数据的话,可能会造成严重的锁等待。
    • 可以保证主从时insert .. select一致性,但大量insert时并发效率很低
  • 前默认模式(模式为1)
    • 不再用锁方式,改为mutex,先使用新方式预判一个动作大约会插入多少数据量,首先分配10个自增ID,用不完也不回收。当其它session请求自增ID时,会造成自增列自增空洞,不过影响不大。
    • 如果遇到不确定的情况,如load data , insert select 时会继续使用旧模式,使用表级别锁,直到动作完成才会释放表级别自增锁。
  • 新方式(模式为2,8.0.3开始默认为2)
    • 模式为1时有退化,但是,由于binlog format=row时可以保证主从一致性,在保证主从一致性的前提下,自增锁就可以统一退化成mutex模式,总是预估数据量、快速分配并释放,这样可以提高并发度。
    • 不退化,古老版本不适合replication环境,可能造成主从数据不一致。但是8.0.3开始为默认值了,同样的binlog_format默认值也是row了。

InnoDB自旋锁 InnoDB spin lock

自旋锁 保护共享资源而提出的锁机制,和互斥锁类似,在任何时刻下都只能有一个持有者,控制事务并发时CPU时间片分配。

可以利用自旋锁的状态来判断InnoDB线程内部争用严重与否。

  • 用于控制InnoDB内部线程调度而存在着的轮询检测
  • innodb_spin_wait_delay,控制轮询间隔,默认为6毫秒。(A线程获取CPU时间片后,B线程每隔6毫秒尝试获取CPU时间片的资源。)
  • 当CPU负载非常高的时候可能也无法保证所有线程都能被合理的分配,这时会导致线程处于休眠状态,spin round 可能也会很高。

另一种描述方式:

  • 保障innodb内部线程的资源分配,innodb内部有很多工作线程,每个线程都要抢CPU的时间片。
  • 自旋锁来保障线程公平的分配CPU时间片。A线程获取CPU时间片后,B线程轮询尝试获取CPU时间片的资源。
  • 当CPU负载非常高的时候可能也无法保证所有线程都能被合理的分配,这时会导致线程处于休眠状态(长时间获得不到资源,会识别为高负载,转为sleep)。

通过自旋锁状态来判断数据库负载

  • 查看spin lock wait

    mysql> show engine innodb status\G

    ----------
    SEMAPHORES
    ----------
    OS WAIT ARRAY INFO: reservation count 239413
    OS WAIT ARRAY INFO: signal count 560637
    RW-shared spins 0, rounds 1028345, OS waits 118311
    RW-excl spins 0, rounds 3590208, OS waits 45541
    RW-sx spins 805351, rounds 5406426, OS waits 61835 Spin rounds per wait: 1028345.00 RW-shared, 3590208.00 RW-excl, 6.71 RW-sx
    ------------
    - RW-shared spins 0 自旋0次, rounds 1028345 循环1028345圈, OS waits 118311 请求不到便sleep,sleep次数。
    - OS waits / rounds
    - 118311 / 1028345= 0.115
    - 45541 / 3590208 = 0.0127
    - 61835 / 5406426 = 0.0114
    • rounds, 表示spin一次空转多少圈,也就是返回来询问的次数。

      • OS waits,表示sleep。当突然增长比较快时,说明latch争用比较严重。

        • 如果OS waits值比较高,说明latch争用比较严重。
      • OS waits/rounds 超过1% 说明系统负载比较高。
      • OS wait 比较大的话, 重点查buffer pool是否够用,以及是否有很多SQL没有使用索引,导致持有innodb page时间较长。
    ----------
    SEMAPHORES
    ----------
    OS WAIT ARRAY INFO: reservation count 596113
    OS WAIT ARRAY INFO: signal count 846843
    RW-shared spins 0, rounds 4277086, OS waits 137734
    RW-excl spins 0, rounds 22496950, OS waits 218313
    RW-sx spins 637341, rounds 11383745, OS waits 170045
    Spin rounds per wait: 4277086.00 RW-shared, 22496950.00 RW-excl, 17.86 RW-sx
    218313/22496950 = 0.0097
    170045/11383745 = 0.0149

InnoDB 行锁

  • 默认都是加lock_ordinary锁

  • 如果是唯一索引列上的等值查询,则退化成lock_rec_not_gap

  • 所有版本,非唯一索引列上的范围查询,遇到第一个不符合条件的记录也会加上lock_ordinary。

  • 8.0.18版本以前,主要指<=场景:唯一索引列上的范围查询,遇到第一个不符合条件的记录也会加上lock_ordinary ,在RC下会释放,RR下不会释放。

  • 8.0.18版本以前,非唯一索引列上的等值查询,向右遍历遇到第一个不符合条件的记录时,先加上lock_ordinary,再退化成lock_gap。

锁排查可以用的视图和数据字典

mysql> show engine innodb status \G
mysql> select * from performance_schema.data_lock_waits;
mysql> select * from performance_schema.data_locks;
mysql> select * from performance_schema.metadata_locks;

查看InnoDB锁

  • 查看InnoDB锁

    • show global status
Innodb_row_lock_current_waits 当前等待的行锁数量
(这个可能不准确。当前即便没有发生,可能也大于0 .使用 select count(*) from sys.innodb_lock_waits 来确认是否真有行锁发生。)
Innodb_row_lock_time 请求行锁总耗时(ms)
Innodb_row_lock_time_avg 请求行锁平均耗时(ms)
Innodb_row_lock_time_max 请求行锁最大耗时(ms)
Innodb_row_lock_waits 行锁发生次数
  • show processlist

  • show engine innodb status

  • sys var: innodb_status_output & innodb_status_output_locks

  • sys.innodb_lock_waits & sys.schema_table_lock_waits

  • pfs.data_locks , 老版本是 innodb_locks

  • pfs.data_lock_waits

  • pfs.metadata_locks

InnoDB 行锁兼容性

请求的锁类型 请求的锁类型 请求的锁类型 请求的锁类型
lock_ordinary lock_rec_not_gap lock_gap lock_insert_intention
已获得的锁类型 lock_ordinary X X O X
已获得的锁类型 lock_rec_not_gap X X O O
已获得的锁类型 lock_gap O O O X
已获得的锁类型 lock_insert_intention O O O O
  • gap只和insert intention锁冲突

  • insert intention和任何锁都不冲突,除非也在相同位置做意向插入锁

  • 先获得意向插入锁的,再尝试上gap lock是可以的

  • 但是反过来 ,先获得gap lock的,再尝试加上意向插入锁便会阻塞,

  • 原因是:先获得意向插入锁时,实际上插入已经成功,意向插入锁会被转变为对具体记录的ordinary 或 rec_not_gap ,此时二者都与lock gap兼容。

InnoDB 读模式

快照读和当前读。

快照读,snapshot read

  • 基于read view 读可见版本,不加锁
  • start transaction with consistent read + select
  • 普通select
  • 一致性快照读需要RR
  • 发起RR级别,再发起快照读,再执行select。

快照 read view

  • 由基于某个时间点的一组InnoDB内部活跃事务构建而成的列表
  • 发起一个快照读时,将当前InnoDB内部活跃事务加入列表,活跃事务会记录影响了哪些数据。
  • 读数据时,每条数据头部信息都有数据最新事务的id版本号,可以判断读到数据版本号和read view的关系, 大于小于还是在范围内, 来确定是要直接读版本,还是要读旧版本数据。

当前读,current read

  • 读(已提交的)最新版本,并加锁
  • S锁,select ..lock in share mode
  • X锁,select ..for update /DML

思考和讨论

  1. 那些情况下会触发整个实例都可能 不可读写 的全局锁?

  2. 用xtrabackup备份全实例数据时,会造成锁等待吗? 如果是mysqldump呢?

  3. 会话1发起backup lock,会话2执行mysqldump/xtrabackup备份,会被阻塞吗?

    mysql1> begin;
    Query OK, 0 rows affected (0.00 sec) mysql1> flush table with read lock;
    Query OK, 0 rows affected (0.00 sec) mysql1> create database oo;
    ERROR 1223 (HY000): Can't execute the query because you have a conflicting read lock mysql2> create database oo;
    --hang
    mysql3> select * from metadata_locks;
    +-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+-------------------+-----------------+----------------+
    | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID |
    +-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+-------------------+-----------------+----------------+
    | GLOBAL | NULL | NULL | NULL | 139619211751216 | SHARED | EXPLICIT | GRANTED | lock.cc:1035 | 63 | 43 |
    | COMMIT | NULL | NULL | NULL | 139619186354560 | SHARED | EXPLICIT | GRANTED | lock.cc:1110 | 63 | 43 |
    |*GLOBAL | NULL | NULL | NULL | 139618850829760 | INTENTION_EXCLUSIVE | STATEMENT |*PENDING | lock.cc:747 | 65 | 5 |
    | TABLE | performance_schema | metadata_locks | NULL | 139619054809168 | SHARED_READ | TRANSACTION | GRANTED | sql_parse.cc:6052 | 64 | 261 |
    +-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+-------------------+-----------------+----------------+
    4 rows in set (0.01 sec)

    换一个顺序

    mysql1> lock instance for backup;
    Query OK, 0 rows affected (0.00 sec) mysql3> select * from metadata_locks;
    +-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+------------------------+-----------------+----------------+
    | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID |
    +-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+------------------------+-----------------+----------------+
    |*BACKUP LOCK | NULL | NULL | NULL | 139619211751216 | SHARED | EXPLICIT | GRANTED | sql_backup_lock.cc:101 | 63 | 46 |
    | TABLE | performance_schema | metadata_locks | NULL | 139619054809168 | SHARED_READ | TRANSACTION | GRANTED | sql_parse.cc:6052 | 64 | 263 |
    +-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+------------------------+-----------------+----------------+
    2 rows in set (0.00 sec) mysql2> begin;
    Query OK, 0 rows affected (0.00 sec) mysql2> flush table with read lock;
    Query OK, 0 rows affected (0.00 sec) mysql3> select * from metadata_locks;
    +-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+------------------------+-----------------+----------------+
    | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID |
    +-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+------------------------+-----------------+----------------+
    | BACKUP LOCK | NULL | NULL | NULL | 139619211751216 | SHARED | EXPLICIT | GRANTED | sql_backup_lock.cc:101 | 63 | 46 |
    |*GLOBAL | NULL | NULL | NULL | 139618851123296 | SHARED | EXPLICIT | GRANTED | lock.cc:1035 | 65 | 10 |
    |*COMMIT | NULL | NULL | NULL | 139618850764288 | SHARED | EXPLICIT | GRANTED | lock.cc:1110 | 65 | 10 |
    | TABLE | performance_schema | metadata_locks | NULL | 139619053138368 | SHARED_READ | TRANSACTION | GRANTED | sql_parse.cc:6052 | 64 | 266 |
    +-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+------------------------+-----------------+----------------+
    4 rows in set (0.00 sec) mysql1> create database oo;
    --hang mysql3> select * from metadata_locks;
    +-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+------------------------+-----------------+----------------+
    | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID |
    +-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+------------------------+-----------------+----------------+
    | BACKUP LOCK | NULL | NULL | NULL | 139619211751216 | SHARED | EXPLICIT | GRANTED | sql_backup_lock.cc:101 | 63 | 46 |
    | GLOBAL | NULL | NULL | NULL | 139618851123296 | SHARED | EXPLICIT | GRANTED | lock.cc:1035 | 65 | 10 |
    | COMMIT | NULL | NULL | NULL | 139618850764288 | SHARED | EXPLICIT | GRANTED | lock.cc:1110 | 65 | 10 |
    |*GLOBAL | NULL | NULL | NULL | 139619186354560 | INTENTION_EXCLUSIVE | STATEMENT | PENDING | lock.cc:747 | 63 | 47 |
    | TABLE | performance_schema | metadata_locks | NULL | 139619053138368 | SHARED_READ | TRANSACTION | GRANTED | sql_parse.cc:6052 | 64 | 267 |
    +-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+------------------------+-----------------+----------------+
    5 rows in set (0.00 sec) mysql2> unlock tables; --release FTWRL
    Query OK, 0 rows affected (0.00 sec) mysql1> lock instance for backup; ----前面的备份锁还没释放
    Query OK, 0 rows affected (0.00 sec) mysql1> create database oo; ----阻塞的DDL事务恢复执行了。
    ERROR 1007 (HY000): Can't create database 'oo'; database exists mysql1> create database ooo; ----再执行一个DDL,成功。此时备份锁还在呢。
    Query OK, 1 row affected (0.21 sec) mysql3> select * from metadata_locks; ---备份锁还在噢。
    +-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+------------------------+-----------------+----------------+
    | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID |
    +-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+------------------------+-----------------+----------------+
    | BACKUP LOCK | NULL | NULL | NULL | 139619211751216 | SHARED | EXPLICIT | GRANTED | sql_backup_lock.cc:101 | 63 | 46 |
    | TABLE | performance_schema | metadata_locks | NULL | 139619053138368 | SHARED_READ | TRANSACTION | GRANTED | sql_parse.cc:6052 | 64 | 269 |
    +-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+------------------------+-----------------+----------------+
    2 rows in set (0.00 sec)

死锁

  • 如果多个事务都需要访问数据,另一个事务已经以互斥方式锁定该数据,则会发生死锁。
  • 事务A等待事务B,同时事务B等待事务A,会产生死锁
  • InnoDB有死锁检测线程,如果检测到死锁,会马上抛出异常并回滚一个事务,回滚原则为“回滚代价较小的、影响较小的事务”,例如产生undo较少的事务会被回滚。
  • 如何判断事务之间是否会发生死锁?
    • 事务T1需要等待事务T2,画一条T1到T2的线

    • 以此类推

    • 图中如果有回路就表示有死锁。

  • 使用show engine innodb status 可以查看到最后的死锁信息
  • 可以设置innodb_print_all_deadlocks = 1 来使日志中记录全部死锁信息
  • 高并发场景中(秒杀),关闭innodb_deadlock_detect选项,降低死锁检测的开销,提高并发效率。同时降低innodb_lock_wait_timeout,缩短锁等待时间。
  • 表级锁不会发生死锁,但是也无法读写并发执行。

关于死锁

  • 偶尔死锁不可怕,频繁死锁才需要关注

  • 程序中应有事务失败检测及自动重复提交机制

  • 多用小事务,并及时显式提交/回滚

  • 调整事务隔离级别为RC,以消除gap lock,降低死锁发生概率

  • 事务中涉及多个表,或者涉及多行记录时,每个事务的操作顺序都要保持一致,降低死锁概率,最好用存储过程/存储函数固化

  • 通过索引优化SQL效率,降低死锁概率

  • 死锁不是“锁死”,死锁会快速检测到,快速回滚。而“锁死”则是行时间锁等待。

  • innodb_rollback_on_timeout = on 时,一旦sql超时,整个事务回滚。

锁优化

InnoDB锁优化

  • 尽可能让所有的数据检索都通过索引来完成,从而避免InnoDB因为无法通过索引键加锁而升级为全表记录级锁
  • 合理设计索引,让InnoDB在索引键上面加锁的时候尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定而影响其他query执行
  • 尽可能减少范围数据检索过滤条件,降低过多的数据被加上lock_ordinary
  • 多使用primary key或者unique key

MySQL锁优化

  • 避免MyISAM,改用InnoDB
  • 多使用primary key或者unique key
  • 确保所有SQL都能走索引
  • 检查索引定义,提高索引效率
  • 多用等值查询,减少范围查询
  • 避免大事务,长事务

常见SQL的锁模式

select … from 一致性非锁定读 如果是serializable级别:Lock_ordinary|S
lock in share mode Lock_ordinary
for update Lock_ordinary
update/delete Lock_ordinary
update t … where col in (select .. from s ..) s表加Lock_ordinary
普通 insert Lock_insert_intention|X 写入请求检测到有重复值时,会加锁Lock_ordinary|X,可能引发死锁
insert… on duplicate key update Lock_ordinary
insert into t select … from s t表加Lock_rec_not_gap | X s表加Lock_ordinary | S 隔离级别为RC或启用innodb_locks_unsafe_for_binlog时,s表上采用无锁一致性读, 即:RC不加锁,RR加nextkey-lock
create table … select 同 insert.. select
replace 无冲突/重复值时,和insert一样:Lock_insert_intention | X, 否则Lock_ordinary | X
replace into t select .. from s where s表加Lock_ordinary
auto_increment列上写新数据时 索引末尾加 record lock
请求自增列计数器时,InnoDB使用一个auto-inc mutex, 但只对请求的那个SQL有影响(lock_mode = 1 时) --------------------------------
有外键约束字段上进行insert/update/delete操作时 除了自身的锁,还会在外表约束列上同时加Lock_rec_not_gap
nextkey-lock 只发生在RR隔离级别下

MySQL锁:02.InnoDB锁的更多相关文章

  1. MySQL优化篇系列文章(二)——MyISAM表锁与InnoDB锁问题

    我可以和面试官多聊几句吗?只是想... MySQL优化篇系列文章(基于MySQL8.0测试验证),上部分:优化SQL语句.数据库对象,MyISAM表锁和InnoDB锁问题. 面试官:咦,小伙子,又来啦 ...

  2. MySQL · 特性分析 · innodb 锁分裂继承与迁移

    http://mysql.taobao.org/monthly/2016/06/01/ innodb行锁简介 行锁类型 LOCK_S:共享锁 LOCK_X: 排他锁 GAP类型 LOCK_GAP:只锁 ...

  3. MySQL 5.7 InnoDB锁

    简介 参考https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html#innodb-gap-locks. InnoDB引擎实现了标准的行级别 ...

  4. mysql 开发进阶篇系列 7 锁问题(innodb锁争用情况及锁模式)

    1 .获取innodb行锁争用情况 1.1 通过检查innodb_row_lock状态变量来分析系统上的行锁的争夺情况 SHOW STATUS LIKE 'innodb_row_lock%' 通过in ...

  5. 【锁】Innodb锁

    InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题.下面我们先介绍一点背景知识 ...

  6. MySQL InnoDB锁机制

    概述: 锁机制在程序中是最常用的机制之一,当一个程序需要多线程并行访问同一资源时,为了避免一致性问题,通常采用锁机制来处理.在数据库的操作中也有相同的问题,当两个线程同时对一条数据进行操作,为了保证数 ...

  7. Innodb 锁系列2 事务锁

    上一篇介绍了Innodb的同步机制锁:Innodb锁系列1 这一篇介绍一下Innodb的事务锁,只所以称为事务锁,是因为Innodb为实现事务的ACID特性,而添加的表锁或者行级锁. 这一部分分两篇来 ...

  8. MySQL数据恢复和复制对InnoDB锁机制的影响

    MySQL通过BINLOG记录执行成功的INSERT,UPDATE,DELETE等DML语句.并由此实现数据库的恢复(point-in-time)和复制(其原理与恢复类似,通过复制和执行二进制日志使一 ...

  9. mysql InnoDB锁等待的查看及分析

    说明:前面已经了解了InnoDB关于在出现锁等待的时候,会根据参数innodb_lock_wait_timeout的配置,判断是否需要进行timeout的操作,本文档介绍在出现锁等待时候的查看及分析处 ...

随机推荐

  1. 结合实战和源码来聊聊Java中的SPI机制?

    写在前面 SPI机制能够非常方便的为某个接口动态指定其实现类,在某种程度上,这也是某些框架具有高度可扩展性的基础.今天,我们就从源码级别深入探讨下Java中的SPI机制. 注:文章已收录到:https ...

  2. 还不懂Java高并发的,建议看看这篇阿里大佬的总结,写的非常详细

    前言 进程是计算机中程序关于某几何数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位.是操作系统结构的基础 线程可以说是轻量级的进程,是程序执行的最小单位,使用多线程而不用多进程去进行并发程 ...

  3. Druid配置和初始化参数 转发地址图片有

    配置数据源 1.添加上 Druid 数据源依赖. <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dep ...

  4. 怎么用思维导图软件iMindMap整理发文思路

    如果你是一个普通的博客作者,那么你就应该明白在枯竭时寻找灵感就像是一场噩梦,即使你有一千个想法,但是你无法将它们关联起来也是无用的,所以,为什么不试试iMindMap思维导图呢,尝试创新,进行组建,你 ...

  5. 苹果电脑怎么给浏览器安装Folx扩展程序

    Folx是一款MacOS专用的老牌综合下载管理软件,它的软件界面简洁,应用简单方便,下载管理及软件设置灵活而强大.Folx不但能够进行页面链接下载.Youtube视频下载,而且还是专业的BT下载工具. ...

  6. linux(cemtos7.x)安装docker

    卸载旧版本 yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest ...

  7. yum安装软件时报错libmysqlclient.so.18()(64bit)

    错误信息 yum -y install sysbench 安装sysbench提示缺少依赖包如下图: 主要原因 缺少Percona-XtraDB-Cluster-shared-55-5.5.37-25 ...

  8. C#设计模式-桥接模式(Bridge Pattern)

    引言 例如我有好几个项目,需要外包出去做各种类型的测试,不同的公司基础费用不同,不同的测试类型价格也是不同的.此时不同的项目选择不同的公司和不同类型的测试进行测试价格都是不同的.于是我们可以创建一个项 ...

  9. angular11源码探索[DoCheck 生命周期和onChanges区别]

    网站 https://blog.thoughtram.io/ https://juristr.com/ https://www.concretepage.com/angular/ https://ww ...

  10. Java基础教程——异常处理详解

    异常处理 好程序的特性 可重用性 可维护性 可扩展性 鲁棒性 |--|--Robust的音译 |--|--健壮.强壮之意 |--|--指在异常和危险情况下系统依然能运行,不崩溃 Java中,写下如下代 ...