欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

2 s锁是什么_innodb存储引擎读书笔记:锁

发布时间:2025/10/17 编程问答 36 豆豆
生活随笔 收集整理的这篇文章主要介绍了 2 s锁是什么_innodb存储引擎读书笔记:锁 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

myisam引擎的锁是表锁,在并发插入时性能较差。

innodb实现了两种行级锁:

  • 共享锁(S lock)

  • 排他锁(X lock)

  • 当一个事务获取了行r的共享锁是,其他的事务也可以获取行r的共享锁,如果其他事务想获取行r的排他锁,必须等待共享锁释放。

    innodb允许行级锁和表级锁同时存在。

    innodb实现了意向锁,意向锁是表级锁。意向锁有两种:

  • 意向共享锁(IS lock):表示事务想获取表中某几行的共享锁

  • 意向排他锁(IX lock):表示事务想获取表中某几行的排他锁

  • 意向锁不会阻塞除全表扫描之外的任何请求。

    information_schema.INNODB_TRX表的字段有:

  • trx_id:innodb引擎内部唯一的事务id

  • trx_state:事务的当前状态

  • trx_started:事务的开始时间

  • trx_request_lock_id:如果trx_state为LOCK WAIT,则此字段的值表示事务等待的锁的id;如果trx_state不为LOCK WAIT,则此字段为null

  • trx_wait_started:事务开始等待的时间点

  • trx_weight:事务的权重,反映了一个事务修改和锁住的行数。当发生死锁需要回滚的时候,innodb会选择权重最小的事务进行回滚。

  • trx_mysql_thread_id:事务对应的线程的id

  • trx_query:事务中的sql

  • information_schema.innodb_locks表的字段有:

  • lock_id:锁的id

  • lock_trx_id:获取了锁的事务的id

  • lock_mode:锁的模式

  • lock_type:锁的类型,表锁还是行锁

  • lock_table:对哪个表加了锁

  • lock_index:对哪个索引加了锁

  • lock_space:表空间的id

  • lock_page:被锁住的页的数量,lock_type为表锁时该字段为null

  • lock_rec:被锁住的行的数量,lock_type为表锁时该字段为null

  • lock_data:被锁住的行的主键,lock_type为表锁时该字段为null

  • information_schema.innodb_lock_waits的字段有:

  • requesting_trx_id:申请锁的事务的id

  • requesting_lock_id:申请的锁的id

  • blocking_trx_id:哪个事务阻塞了requesting_trx_id

  • blocking_lock_id:哪个锁阻塞了requesting_lock_id

  • 示例如下(为什么blocking_lock_id和requested_lock_id不是同一个锁?导致当前事务阻塞的锁竟然不是当前事务正在请求的锁?确实不一样,事务730FEE对行记录加了X锁,而事务7311F4要对该行记录加S锁。):

    一致性的非锁定读:innodb通过多版本控制读取当前时刻数据库中的行记录。如果读取的行记录正在被delete、update,读取操作不等待行上锁的释放,而会去读取该行的一个快照。这个快照实际上是undo段。一致性的非锁定读是innodb默认的读取方式。

    多版本并发控制MVCC:multi version concurrency controll。

    多版本指的是快照有多个版本。

    在repeatable read(innodb默认的事务隔离级别)和read committed下,innodb使用一致性非锁定读,但是对快照的定义不同。

    read committed下,一致性非锁定读总是读取最新的快照。

    repeatable read下,一致性非锁定读总是读取事务开始时的行数据版本。

    (突然想到的一个疑问:事务内的每一次对行记录的操作,是否会操作完就释放锁?还是说会等到事务提交之后一起释放?

    验证:

    先在事务A中获取行记录上的S锁:

    再在事务B中获取该行记录上的X锁:

    可以看到事务B阻塞了。查看INNODB_TRX表也可以看到如下信息:

    因此说明了事务中获取的S锁要等到事务结束后再释放,X锁也是如此。这个特性与事务的隔离级别无关。

    )

    查看事务隔离级别:

    select @@tx_isolation;

    设置事务隔离级别:

    set [global | session] transaction isolation level Read uncommitted | Read committed | Repeatable Read | Serializable;

    如果选择global,则隔离级别将应用于之后新建的session,而当前已经存在的session(包括当前session)不受影响。

    如果选择session,则隔离级别将应用于当前session内之后的所有事务,其他已经存在的session和之后新创建的session均不受影响。

    如果事务隔离级别为repeatable read,则session A中的三次读都会读到id=1的记录。如果事务隔离级别为read committed,则session A中的前两次读都会读到id=1的记录,但是第三次读会返回空集。(已验证)

    innodb中select操作默认使用一致性非锁定读。

    如果到对select操作加锁:

        select ... for update:对读取的行记录加X锁,其他事务如果要在该行上加任何锁都会被阻塞。

        select ... in share mode:对读取的行记录加S锁,其他事务可以对该行加S锁,但是要加X锁就会被阻塞。

    注意:

    1. select操作加锁后,其他事务仍然可以执行一致性非锁定读select操作。

    2. 事务提交后select上的锁才会被释放。默认情况下,执行一条语句就是一次事务,所以select ... for update和select ... in share mode执行完后锁就被释放。

    AUTO-INC Locking:在执行插入操作时,自增长列(一般就是指主键)的值由自增长计数器确定。从自增长计数器中取值时,需要先上锁。

    这种锁是表级锁,但是却不会在事务完成之后才释放,而是在完成插入操作后立即释放。

    参数innodb_autoinc_lock_mode:

    取0时表示上文所提的加锁方式;

    取1(默认值)时表示在进行simple inserts(插入前就能确定插入的行数)时采用互斥量对计数器进行累加,在进行bulk inserts(插入前不能确定插入的行数)时采用上文提到的加锁方式。

    取2时表示对于所有的insert操作都采用互斥量。

    innodb中,如果一个表中定义了自增长列,则该列上必须建索引,如果联合索引中包含该列,则该列必须是第一列。

    innodb中,外键列会自动被加上一个索引,避免表锁。

    插入或更新外键列时,首先会select父表,为保证数据一致,会使用select ... lock in share mode,而不是一致性非锁定读。

    innodb中行锁分类:

  • record lock:行记录上的锁

  • gap lock:间隙锁,锁定一个范围,但不包含记录本身

  • next-key lock:等价于record lock + gap lock。

  • innodb中,默认的事务隔离级别是repeatable read。这种隔离级别下,next-key lock是默认的行记录锁定算法。

    repeatable read隔离级别下,先在事务A中执行select * from t where a < 6 lock in share mode,再在事务B中执行insert into t select 5或insert into t select 6,事务B会阻塞住。如果在事务B中执行insert into t select 9,则会直接执行成功。事务A中的select会被加上next-key share lock。

    repeatable read隔离级别下,先在事务A中执行select * from t where a = 7 lock in share mode,再在事务B中执行insert into t select 5或insert into t select 6,则会直接执行成功。事务A中的select会被加上record share lock。

    lost update:

    场景(时间线顺序):

  • 事务1查询一行记录

  • 事务2也查询该行记录

  • 事务1更新该行记录

  • 事务2更新该行记录

  • 结果是事务1的更新被覆盖了。

    如何避免?

    事务在查询时就加上排他锁。

    脏数据:已被修改但还未被提交的数据。

    脏读:一个事务读到另一个事务中的脏数据。

    隔离级别为read uncommitted时就会出现脏读。

    不可重复读:同一个事务内,多次读同一行记录,读到的数据不同。原因是,在该事务内的两次select操作之间,其他事务修改了该行记录,并提交了。

    隔离级别为read committed时会出现不可重复读。

    事务之间可能会因锁的问题产生阻塞。

    innodb_lock_wait_timeout:超时时间,可以在运行时修改。默认是50s。

    innodb_rollback_on_timeout:超时是是否对事务进行回滚,不可在运行时修改。默认是OFF。

    mysql中,事务中抛出异常时,mysql一般不会对事务进行回滚,而是等待用户决定是要提交还是回滚。但是发生死锁时,innodb会自动对其中一个事务进行回滚。

    总结

    以上是生活随笔为你收集整理的2 s锁是什么_innodb存储引擎读书笔记:锁的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。