实验11.2 隔离级别和锁的使用

更新于 2026年10月10日 版权声明
实验11.2 隔离级别和锁的使用

【实验目的】

①理解MySQL的隔离级别。

②理解MySQL的锁机制。

③理解事务加锁的机制。

【实验内容】

①创建事务1和事务2,设置事务隔离级别为“READ-UNCOMMITTED”。在事务1中执行更新语句,在事务2中执行查询语句,比较执行结果。

②创建事务1和事务2,设置事务隔离级别为“READ-COMMITTED”。在事务1中执行更新语句,在事务2中执行查询语句,比较执行结果。

③创建事务1和事务2,设置事务隔离级别为“REPEATABLE-READ”。在事务1中执行更新语句,在事务2中执行查询语句,比较执行结果。

④创建事务1和事务2,对事务设置表级别的S锁和X锁,比较事务1和事务2的执行结果。对事务1和事务2模拟死锁,查看死锁和解除锁。

【实验步骤】

(1)设置事务隔离级别为“READ⁃UNCOMMITTED”

创建事务1和事务2,设置事务隔离级别为“READ⁃UNCOMMITTED”。在事务1中执行更新语句,在事务2中执行查询语句,比较执行结果。

①单击“WIN+R”键,输入“cmd”,回车即可打开命令提示符窗口;或者在屏幕左下方搜索框输入“cmd”,可以找到cmd,单击即可,如图11.8所示。

图示

图11.8 打开命令行

②输入“title 事务1”的命令,回车后,设置会话窗口名称为“事务1”。

③输入“mysql -uroot -p”的命令,然后回车,会提示输入密码,输入密码后即可连接MySQL,如图11.9所示。

图示

图11.9 建立事务1会话

④重复步骤②和③,建立名称为“事务2”的会话窗口,并连接MySQL,如图11.10所示。

图示

图11.10 建立事务2会话

⑤分别在两个会话窗口中,查看和修改隔离级别。输入下面的SQL语句并回车执行,查看当前设置的事务隔离级别。

show variables like 'transaction_isolation';

或者

select @@transaction_isolation;

然后输入下面SQL语句并回车执行,修改会话窗口的隔离级别为“读未提交”,如图11.11和图11.12所示。

set session transaction_isolation  = 'read-uncommitted';

图示

图11.11 查看和修改事务1隔离级别

图示

图11.12 查看和修改事务2隔离级别

⑥在事务1会话窗口,依次输入下面命令并执行:

use sales;
select * from products;
begin;
update products set price=1 where pid ='p01';
select * from products;

事务1修改了products表中p01的价格,但未提交,如图11.13所示。

⑦在事务2会话窗口,依次输入下面命令并执行:

use sales;
select * from products;

查询products表,发现产品p01的price为1,如图11.14所示,事务2读的是事务1未提交的数据,即事务2发生了脏读现象。

⑧再回到事务1会话窗口,输入下面命令并执行:

rollback;
select * from products;

图示

图11.13 事务1更新操作

图示

图11.14 事务2读到脏数据

事务1进行了回滚操作,然后再查询products表,发现p01的price又变成0.5,如图11.15所示。

图示

图11.15 事务1进行ROLLBACK操作

(2)设置事务隔离级别为“READ⁃COMMITTED”

创建事务1和事务2,设置事务隔离级别为“READ⁃COMMITTED”。在事务1中执行更新语句,在事务2中执行查询语句,比较执行结果。

①分别在两个会话窗口中,输入下面的SQL语句并回车执行,修改隔离级别为“读已提交”。

SET SESSION TRANSACTION_ISOLATION  = 'READ-COMMITTED';

②重复前一个实验的步骤⑥—⑧,即在事务1会话窗口,依次输入下面命令并执行:

use sales;
select * from products;
begin;
update products set price=1 where pid ='p01';
select * from products;

事务1修改了products表中p01的价格,但未提交,如图11.16所示。

图示

图11.16 事务1进行更新操作

然后在事务2会话窗口,依次输入下面命令并执行:

use sales;
select * from products;

查询products表,发现读出的products表的产品p01的price为0.5,如图11.17所示,事务2读的是事务1提交的数据,即事务2未发生脏读现象。

图示

图11.17 事务2没有读到脏数据

最后回到事务1会话窗口,输入下面命令并执行:

rollback;
select * from products;

事务1进行了回滚操作,然后再查询products表,发现p01的price又变成0.5,如图11.18所示。

图示

图11.18 事务1进行ROLLBACK操作

(3)设置事务隔离级别为“REPEATABLE⁃READ”

创建事务1和事务2,设置事务隔离级别为“REPEATABLE⁃READ”。在事务1中执行更新语句,在事务2中执行查询语句,比较执行结果。

①分别在两个会话窗口中,输入下面的SQL语句并回车执行,修改隔离级别为“可重复读”,如图11.19和图11.20所示。

set session transaction_isolation  = 'repeatable-read';
select @@transaction_isolation;

图示

图11.19 修改事务1隔离级别为“可重复读”

图示

图11.20 修改事务2隔离级别为“可重复读”

②在事务1会话窗口,依次输入下面命令并执行:

use sales;
begin;
select * from products;
update products set price= price-0.5 where pid ='p06';
select * from products;

事务1先查询了products表,p06的price为2,然后修改了products表中p06的价格,但未提交,再查询products表的p06的price为1.5,如图11.21所示。

图示

图11.21 事务1查询结果

③在事务2会话窗口,依次输入下面命令并执行:

use sales;
begin;
select * from products;(https://www.daowen.com)

查询products表,发现产品p06的price仍然为2,如图11.22所示。

图示

图11.22 事务2的查询结果

④再回到事务1会话窗口,输入下面命令并执行:

commit;
select * from products;

事务1进行了提交操作,然后再查询事务1的products,发现p06的price仍然为1.5,如图11.23所示。

图示

图11.23 事务1提交后的查询结果

⑤再回到事务2会话窗口,输入下面命令并执行:

select * from products;commit;select * from products;

事务2在事务1进行提交操作前,查询products表的p06的price是2,事务2在事务1进行提交操作后,再次查询products表,发现p06的price仍然是2,证明事务2的隔离级别是可重复读。事务2进行提交操作后,再次查询products表,这时候p06的price为1.5,如图11.24所示。

图示

图11.24 事务2进行提交操作前后的查询结果

(4)对事务设置表级别的S锁和X锁

创建事务1和事务2,对事务设置表级别的S锁和X锁,比较事务1和事务2的执行结果。对事务1和事务2模拟死锁,查看死锁和解除锁。

①创建事务1会话窗口,并连接MySQL。依次输入下面命令并执行:

use sales;begin;lock tables agents read;select * from agents;update agents set percent=5 where aid='a01';select * from  orders;

对agents加表级别的读锁(S锁),加入S锁后可以查询agents表,但不能对agents表进行更新操作,也不能对其他表进行查询操作,因为其他表没有加锁,如图11.25所示。

图示

图11.25 事务1加表级别的S锁

②创建事务2会话窗口,并连接MySQL。依次输入下面命令并执行:

show open tables where in_use > 0;
use sales;
select * from agents;

在事务1没有通过“unlock tables”命令解锁表之前,输入SQL语句:“show open tables where in_use > 0”,显示加锁的表,然后设置当前数据库,并查询agents表,发现可以访问该表,说明不同事务会话窗口可以共享表的读锁,如图11.26所示。

图示

图11.26 事务2查询加S锁的agents 表

③回到事务1会话窗口,依次输入下面命令并执行:

unlock tables;
lock tables agents write;
show open tables where in_use > 0;
update agents set percent=5 where aid='a01';
select * from  agents;
select * from  orders;

对于事务1,对agents 加表级别的X锁,加了X锁后可以对agents 表进行更新和读操作,但不能对其他表查询,因为其他表没有加锁,如图11.27所示。

④回到事务2会话窗口,依次输入下面命令并执行:

show open tables where in_use > 0;
select * from  agents;

在事务1没有通过“unlock tables”命令解锁表之前,显示加锁的agents 表,然后查询agents 表,发现不能访问该表,只能等待agents表解锁,如图11.28所示。

图示

图11.27 事务1对agents 表加X锁

图示

图11.28 事务2不能查询加了X锁的agents表

⑤回到事务1会话窗口,依次输入下面命令并执行:

unlock tables;
use sales;
select * from  products;
begin;
update products set price=1 where pid='p01';

事务1更新products表中的p01的price数值。

⑥回到事务2会话窗口,依次输入下面命令并执行:

use sales;
select * from  products;
begin;
update products set price=2 where pid='p02';

事务2更新products表中的p02的price数值。

⑦回到事务1会话窗口,输入下面命令并执行:

update products set price=1.5 where pid='p02';

事务1又更新products表中p02的price数值,事务1进入等待状态。

⑧回到事务2会话窗口,输入下面命令并执行:

update products set price=2 where pid='p01';

事务2更新products表中p01的price数值,事务1封锁了p01,又需要封锁p02,事务2封锁了p02,又需要封锁p01,这样就形成了死锁。当出现死锁以后,事务1直接进入等待,事务2检测到死锁,然后中断事务2后,事务1最后一条更新语句完成,耗时11.87秒,如图11.29和图11.30所示。

图示

图11.29 事务1进入等待,直到事务2中断

图示

图11.30 事务2进入死锁状态

↑上一章 ↓下一章
关注公众号获取验证码
复制内容需要验证码(7.99元/天)