wordpress制作视频站,国外买域名的网站,wordpress网站转移,网页视频下载神器聊聊不同隔离级别下#xff0c;都会使用哪些锁#xff1f; 1. MySQL 锁机制
对于 MySQL 来说#xff0c;如果只支持串行访问的话#xff0c;那么其效率会非常低。因此#xff0c;为了提高数据库的运行效率#xff0c;MySQL 需要支持并发访问。而在并发访问的情况下…聊聊不同隔离级别下都会使用哪些锁 1. MySQL 锁机制
对于 MySQL 来说如果只支持串行访问的话那么其效率会非常低。因此为了提高数据库的运行效率MySQL 需要支持并发访问。而在并发访问的情况下会发生各种各样的问题例如脏读、不可重复读、幻读等问题。为了解决这些问题就出现了事务隔离级别
本质上事务隔离级别就是为了解决并发访问下的数据一致性问题的。不同的事务隔离级别解决了不同程度的数据一致性 我们所说的全局锁、表锁、行级锁等等其实都是事务隔离级别的具体实现。而 MVCC、意向锁则是一些局部的性能优化 2. 事务隔离级别
MySQL 数据库有四大隔离级别
读未提交脏读可以读取到其他事务还没提交的数据。 未提交的数据可能会发生回滚因此我们把该级别读取到的数据称之为脏数据把这个问题称之为脏读读已提交不可重复读该隔离级别的事务能读取到已经提交事务的数据。 因此它不会有脏读问题。但由于在事务的执行中可以读取到其他事务提交的结果所以在不同时间的相同 SQL 查询中可能会得到不同的结果这种现象叫做不可重复读可重复读MySQL 的默认事务隔离级别幻读同一事务范围内读取到的数据是一致的。 但也会有新的问题比如此级别的事务正在执行时另一个事务成功的插入了某条数据两次查询结果记录条数不一样串行化所有事务串行执行。 不用去竞争一个个去执行但是效率也是最低的 当事务读取数据时会获取共享锁以确保数据的一致性。如果有其他事务已经持有排他锁则读取操作需要等待排他锁释放当事务修改数据时会获取排他锁以防止其他事务读取或修改相同的数据。如果有其他事务已经持有共享锁或排他锁则修改操作需要等待相关锁释放
3. MySQL 锁类型
在 MySQL 中有全局锁、表级锁、行级锁三种类型其中比较关键的是表级锁、行级锁
MySQL 锁类型
全局锁表级锁 表锁在 Innodb 存储存储引擎中表锁也用得比较少元数据锁基本上都是数据库自行操作意向锁 行级锁 记录锁某个索引记录的锁间隙锁两个索引记录之间的空隙锁临键锁记录锁 间隙锁自增锁
在 Innodb 存储引擎中我们可以通过下面的命令来查询锁的情况
# 开启锁的日志
set global innodb_status_output_lockson;
# 查看innodb引擎的信息(包含锁的信息)
show engine innodb status\G;查询结果一般如下图所示 上面几种不同类型的锁其各自的关键字为
表级的意向排它锁IXlock mode IX。行级的插入意向锁LOCK_INSERT_INTENTION: lock_mode X locks gap before rec insert intention行级的记录锁LOCK_REC_NOT_GAP: lock_mode X locks rec but not gap行级的间隙锁LOCK_GAP: lock_mode X locks gap before rec行级的 Next-key 锁LOCK_ORNIDARY: lock_mode X
通过上面的命令我们就可以知道不同的事务隔离级别使用了哪些锁了
4. 准备数据测试
CREATE TABLE 2022.price_test (id BIGINT(64) NOT NULL AUTO_INCREMENT,name varchar(32) not null,price INTEGER(4) NULL,PRIMARY KEY (id));INSERT INTO price_test(name,price) values(apple, 10);四种隔离级别
READ UNCOMMITTED读未提交READ COMMITTED读已提交REPEATABLE READ可重复读SERLIALIZABLE序列化
5. 读未提交
打开两个命令行窗口并且都修改事务隔离级别为「读未提交」
// 设置隔离级别
SET session TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
// 查看隔离级别
select transaction_isolation;5.1 读写
事务 A 执行如下命令查询出 id 为 1 记录的 price 值不提交事务
begin;
select * from price_test where id 1;接着事务 B 执行如下命令修改 price 为 20
begin;
update price_test set price 20 where id 1;接着事务 A 再次读取 id 为 1 记录的 price 值。事务 A 读取到了事务 B 未提交的数据这其实就是脏读了
select * from price_test where id 1;【结论】在「读未提交」事务隔离级别下读写是可以同时进行的不会阻塞。
5.2 写写
事务 A 和 事务 B 同时对 id 为 1 的记录进行更新看看是否能够更新成功
先用如下命令在事务 A上边的窗口执行将 price 修改为 15此时事务 A 还未提交。
begin;
update price_test set price 15 where id 1;如下命令在事务 B下边的窗口执行将 price 修改为 20从图中可以看到事务 B 阻塞卡住了
begin;
update price_test set price 20 where id 1;【结论】在「读未提交」事务隔离级别下写写不可以同时进行的会阻塞 通过查看锁信息可以看到其是加上一个行级别的记录锁如下图所示 如果指定了非索引的列作为查询条件是否会触发间隙锁呢 插入一条数据
INSERT INTO 2022.price_test (id, name, price) VALUES (2, orange, 30);在事务 A 执行如下命令select * from price_test where price 15 for update;查询 price 15 的记录 接着我们在事务 B 执行如下命令select * from price_test where price 5 for update;查询 price 5 的记录。从如下结果可以看到事务 B 阻塞住了 3. 事务 A 查看锁的情况如下图所示 从上图可以看出MySQL 只是加上了一个记录锁并没有加间隙锁
5.3 总结
在「读未提交」隔离级别下读写操作可以同时进行但写写操作无法同时进行。与此同时该隔离级别下只会使用行级别的记录锁并不会用间隙锁
6. 读已提交
设置一下隔离级别为「读已提交」
SET session TRANSACTION ISOLATION LEVEL READ COMMITTED;6.1 读写
事务 A 执行如下命令查询出 id 为 1 记录的 price 值不提交事务
begin;
select * from price_test where id 1;接着事务 B 执行如下命令修改 price 为 20
begin;
update price_test set price 20 where id 1;接着事务 A 再次读取 id 为 1 记录的 price 值。事务 A 未读取到了事务 B 未提交的数据未产生脏读。
select * from price_test where id 1;6.2 写写
测试同时对 id 为 1 的数据进行更新
事务 A 执行如下命令
begin;
update price_test set price 15 where id 1;接着事务 B 执行如下命令
begin;
update price_test set price 20 where id 1;事务 B 阻塞了。查看下锁信息如下图所示 可以看到其锁是一个行级别的记录锁结果和「读未提交」的是一样的 继续看看范围的查询是否会触发间隙锁 事务 A 执行
begin;
select * from price_test where price 5 for update;事务 B 执行
begin;
select * from price_test where price 15 for update;事务 B 会阻塞查看锁信息如下图所示 6.3 总结
在「读已提交」隔离级别下只会使用行级别的记录锁并不会用间隙锁。
6.4 读已提交隔离级别如何解决了【脏读】问题
脏读是在并发事务中一个事务可以读取到另一个未提交事务的数据
在“读已提交”隔离级别下事务只能读取已经提交的数据而不能读取未提交的数据。这意味着当一个事务正在进行修改时其他事务无法读取到该事务所做的修改直到该事务提交
为了实现读已提交隔离级别数据库管理系统通常使用锁机制或多版本并发控制MVCC。锁机制可以确保一个事务在修改数据时对其他事务进行阻塞以防止脏读。而MVCC则通过为每个事务创建不同的数据版本来实现隔离并且只允许事务读取已提交的数据版本
7. 可重复读
我们设置一下隔离级别为「可重复读」
SET session TRANSACTION ISOLATION LEVEL REPEATABLE READ;7.1 读写
事务 A 执行如下命令查询出 id 为 1 记录的 price 值不提交事务
begin;
select * from price_test where id 1;接着事务 B 执行如下命令修改 price 为 20
begin;
update price_test set price 20 where id 1;接着事务 A 再次读取 id 为 1 记录的 price 值。事务 A 未读取到了事务 B 未提交的数据未产生脏读。
select * from price_test where id 1;7.2 写写
同时对 id 为 1 的数据进行更新看看会发生什么
事务 A 执行如下命令
begin;
update price_test set price 15 where id 1;事务 B 执行如下命令
begin;
update price_test set price 20 where id 1;事务 B 阻塞了。查看下锁信息加上一个行级别的记录锁 继续看看范围的查询是否会触发间隙锁 事务 A 执行
begin;
select * from price_test where price 5 for update;事务 B 执行
begin;
select * from price_test where price 15 for update;事务 B 会阻塞查看锁信息如下图所示 可以看到在这里就变成了 Next-Key 锁就是记录锁和间隙锁结合体
7.3 总结
在「可重复读」隔离级别下使用了记录锁、间隙锁、Next-Key 锁三种类型的锁
可重复读存在幻读的问题但实际上在 MySQL 中因为其使用了间隙锁所以在「可重复读」隔离级别下可用加锁解决幻读问题。因此MySQL 将「可重复读」作为了其默认的隔离级别
8. 总结
对于任何隔离级别表级别的表锁、元数据锁、意向锁都是会使用的但对于行级别的锁则会有些许差别
在「读未提交」和「读已提交」隔离级别下都只会使用记录锁不会用间隙锁当然也不会有 Next-Key 锁了对于「可重复读」隔离级别来说会使用记录锁、间隙锁和 Next-Key 锁