索引更新的阻塞
sql
事务1
set AUTOCOMMIT=FALSE;
UPDATE course SET course_id=6 WHERE course_id =1; (6 排他锁 1 )
select * from course where course_id = 6
rollback
commit
事务2
set AUTOCOMMIT=FALSE;
UPDATE course SET course_id=7 WHERE course_id =6; ( 6 是排他锁 7 )
select * from course where course_id = 6
ROLLBACK;
commit;
排他锁与mvcc相遇;
上了排他锁之后,另一个事务中只能阻塞;
数据修改时会根据过滤条件匹配对应的索引,在对应的索引键值上加锁,
如果语句中修改了索引的值,还会在修改后的值上增加锁。
其他事务使用了相同的索引值修改数据不管是否是相同的行均会被阻塞。
索引的增加删除 和更改
insert 阻塞update 和delete
delete 会阻塞update 和delete
for update上的什么锁
FOR UPDATE 锁的行为
锁定行为:FOR UPDATE 会在被检索的行上放置排他锁。
锁定范围:锁定范围取决于查询条件和索引的存在与否。
如果查询条件涉及到主键或唯一索引,则只会锁定匹配的行。
如果查询条件不涉及主键或唯一索引,可能会锁定更多的行或整个表,具体取决于使用的存储引擎和查询的具体情况。
锁定级别:默认情况下,InnoDB 存储引擎使用行级锁,但在某些情况下可能会升级为更高级别的锁。
锁的类型
排他锁(Exclusive Lock, X-Lock):当一个事务获得了排他锁后,其他事务不能对该数据进行任何读写操作,直到锁被释放。
共享锁(Shared Lock, S-Lock):多个事务可以同时获得共享锁,但如果有事务想要获取排他锁,则所有持有共享锁的事务都将被阻塞。
FOR UPDATE 锁的特性
InnoDB 存储引擎:FOR UPDATE 仅适用于 InnoDB 存储引擎,并且必须在事务中使用。
锁定时间:锁定会在事务开始时(例如使用 BEGIN 或 START TRANSACTION 开始事务)生效,并持续到事务结束(使用 COMMIT 或 ROLLBACK)。
锁升级:如果查询没有使用适当的索引,InnoDB 可能会将行级锁升级为表级锁。
阻塞:当一个事务使用 FOR UPDATE 获取锁时,其他想要修改相同数据的事务会被阻塞,直到第一个事务释放锁。
示例
共享锁;
SELECT * FROM table_name WHERE condition LOCK IN SHARE MODE;
- 并发读取
允许多个读取事务:共享锁允许多个事务同时读取同一数据,这有助于提高系统的并发性能。
避免读写冲突:当一个事务对数据加上共享锁后,其他事务只能再对相同数据加上共享锁,而不能加上排他锁。这样就避免了读取事务与写入事务之间的冲突。 - 数据一致性
保证数据一致性:共享锁确保了在同一时刻,多个读取事务可以看到一致的数据版本,这对于需要读取一致数据的应用来说非常重要。
避免脏读:共享锁可以防止事务读取到未提交的数据,即避免了读取脏数据的情况。 - 提高并发性能
减少阻塞:共享锁减少了读取事务之间的阻塞,因为多个读取事务可以并发执行。
减少锁竞争:由于多个事务可以同时持有共享锁,因此减少了锁的竞争,提高了系统的吞吐量。 - 事务隔离级别
乐观锁
MVCC 与锁的关系
读取操作:MVCC 允许事务读取数据的旧版本,而不是等待写入操作完成。这意味着读取操作通常不需要加锁。
写入操作:当一个事务执行写入操作时,MVCC 会在数据行旁边创建一个新的版本,而不是直接修改现有的行数据。这也意味着写入操作通常也不需要加锁。
MVCC 如何避免锁
版本管理:每个数据行都包含了多个版本的信息,包括创建该版本的事务 ID 和删除该版本的事务 ID。
读取一致性:当一个事务执行读取操作时,它会根据自己的事务 ID 和数据行的版本信息来决定哪些版本的数据是可以看到的。这通常是通过一个叫做 Read View 的机制来实现的。
写入操作:当一个事务执行写入操作时,InnoDB 会为数据行创建一个新的版本,并且保留旧版本供其他事务读取。这意味着更新操作实际上是在数据行旁边创建了一个新的版本,而不是直接修改现有的行数据