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存储引擎读书笔记:锁的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: catia过载属性使用方法_CATIA-
- 下一篇: ffmpeg 怎么处理udp音频_STR