整形,对值具有唯一制约条件的数据范围1~5,
已经有数据1、2、3、4、5,此时数据范围已完全填充;
整形,对值有唯一约束的数据范围1和5、
有数据1、5,此时数据范围完全填充;
2 .数据填充了部分数据范围:(未完全填充的数据范围存在数据间隙) )。
整形后的数据范围为1~5,
已经有数据1、2、3、4和5,但没有唯一的约束。
因此,数据范围可以用1~5的数据重复填充;
整形,具有唯一制约条件的数据范围1~5,
已经有数据2、5,此时数据范围没有完全填充,也可以填充1、3、4;
3 .数据范围内没有数据(有间隙) () ) ) ) ) ) )。
如下所示。
整形后的数据范围为1~5,数据范围内目前没有任何数据。
了解完数据全集的结构后,让我们来看看同时发生事务时的问题。
不受控制的并发问题
如果并发事务不受控制,则会出现一些问题。 主要有以下情况。
1 .范围内现有数据更改所致:
找不到更新:如果多个事务选择了同一行,并根据最初选择的值更新了该行。
所有的东西都不知道其他事务的存在,所以最后的更新涵盖了其他事务所进行的更新
脏读:一个事务正在对一个记录进行更改。 在此事务完成并提交之前,此记录处于不一致状态。
此时,另一个事务也会来读取同一条记录。 如果不控制,
第二个事务在读取这些“脏”数据并在此基础上进行进一步处理时,会发生已提交数据的依赖关系。
这种现象叫做“污读”。
2 .范围内的数据量变化所致:
不要重复。 一个事务在读取某个数据后的某个时间再次读取以前读取的数据。
发现读取的数据已更改或部分记录已被删除。
我说这种现象“不能反复读”。
幻读:一个事务在相同的查询条件下重新读取以前检索的数据,
发现其他事务中插入了符合查询条件的新数据。 这种现象称为“幻读”。
可以简单地认为满足条件的数据量发生了变化。
不受控制的并发带来了一系列问题,因为这些问题不能满足我们需要的结果。 因此,为了实现我们希望的结果(隔离级别),需要控制并发。
实现MySQL隔离级别
InnoDB通过锁定的策略支持这些隔离级别。
行锁定包括:
记录锁定
即使索引记录锁、索引记录锁表中没有定义索引,索引记录也将始终被锁定。
在这种情况下,InnoDB会创建一个隐藏的集群索引,并使用该索引锁定记录。
Gap Locks
间隙锁定是索引记录之间的间隙,或第一条记录之前或最后一条记录之后的锁定。
差距锁定是性能和并发性之间权衡的一部分。
没有间隙的数据范围不需要间隙锁定。 因为没有间隙。
下一键锁定
索引记录的记录锁定和索引记录之前的gap lock的组合。
假设索引包含10、11、13和20。
可能的下一个密钥锁定包括以下间隔: 括号表示不包含间隔端点,括号表示包含端点。
负无限大、10 ((10,11 )、13 )、13、20 )、20、正无限大)在最后一个间隔中,next-key锁定在索引的最大值之上。
左右滑动观看
“上界”假记录的值高于索引中的实际值。
实际上,此next-key仅锁定最大索引值之后的间隙,因为上边界不是真正的索引记录。
据此,如果数据在所取得的数据范围中嵌入了所有的数据范围,则此时没有间隙,也不需要gap lock。
如果数据范围内有间隙,则需要根据隔离级别确定间隙是否锁定。
在缺省的REPEATABLE READ隔离级别,除了锁定数据本身外,还必须锁定数据间隙以确保重读。
READ COMMITTED已提交读取。 MySQL在评估where条件后释放不匹配行的记录锁定。
对于update语句,InnoDB执行' semi-consistent '读取,并将最新的提交版本恢复为MySQL。
允许您确定MySQL是否符合更新的where条件。
集中拉伸:
由于唯一索引具有唯一约束,因此如果更改的数据违反唯一约束原则,则会失败。
在where条件下使用辅助索引过滤器时,辅助索引命中条目和相应的聚簇索引都将被锁定。 因此,如果命中锁定的集群索引的其他事务发生更改,则等待锁定。
由于行锁定的增加逐行增加,因此并发可能会发生死锁。
例如,
如果session A锁定了满足条件的集群索引,则可能是s
ession B 已持有该聚簇索引的 Record Locks,而 session B 正在等待 session A 已持有的某聚簇索引的 Record Locks。session A 和 session B 是通过两个不相干的二级索引定位到的聚簇索引。
session A 通过索引 idA,session B通过索引 idB 。
当 where 条件获取的数据无间隙时,无论隔离级别为 rc 或 rr,都不会存在间隙锁。
比如通过唯一索引获取到了已完全填充的数据范围,此时不需要间隙锁。
间隙锁的目的在于阻止数据插入间隙,所以无论是通过 insert 或 update 变更导致的间隙内数据的存在,都会被阻止。
rc 隔离级别模式下,查询和索引扫描将禁用 gap locking,此时 gap locking 仅用于外键约束检查和重复键检查(主要是唯一性检查)。
rr 模式下,为了防止幻读,会加上 Gap Locks。
事务中,SQL 开始则加锁,事务结束才释放锁。
就锁类型而言,应该有优化锁,锁升级等,例如rr模式未使用索引查询的情况下,是否可以直接升级为表锁。
就锁的应用场景而言,在回放场景中,如果确定事务可并发,则可以考虑不加锁,加快回放速度。
锁只是并发控制的一种粒度,只是一个很小的部分:
从不同场景下是否需要控制并发,(已知无交集且有序的数据的变更,MySQL 的 MTS 相同前置事务的多事务并发回放)
并发控制的粒度,(锁是一种逻辑粒度,可能还存在物理层和其他逻辑粒度或方式)
相同粒度下的优化,(锁本身存在优化,如IX、IS类型的优化锁)
粒度加载的安全&性能(如获取行锁前,先获取页锁,页锁在执行获取行锁操作后即释放,无论是否获取成功)等多个层次去思考并发这玩意。