23 mysql的四种事务隔离级别

数据库的隔离级别是在并发度和安全性之间做平衡。mysql支持四种事务隔离级别,分别是:Read Uncommitted(读取未提交内容)]、Read Committed(读取提交内容)、Repeatable Read(可重读)、Serializable(可串行化),这四种隔离级别并发度越来越低,但安全性越来越高。mysql的默认隔离级别是REPEATABLE-READ,即可重复读。本文将详细介绍数据库的四种隔离级别之表现。

1、环境约束

  • win10 64
  • mysql 5.7.27

    2、前提约束

  • 已经安装好数据库
    https://www.jianshu.com/p/74c291a79fa3
  • 确保数据库中已经有一张表t_user,打开命令行,请执行以下代码:
# 登录到mysql
mysql -uroot -pzhangli
# 创建一张表
create table t_user(id int,name varchar(20));
# 插入2条记录
insert into t_user(id,name) values(1,'ali');
insert into t_user(id,name) values(2,'zhangli');

3、操作步骤

3.1 准备工作

打开两个命令行,都登录到mysql,左边的表格命名为1,右边的表格命名为2,如下图:
打开两个命令行登录到mysql
由上图课件,mysql的默认隔离级别是Repeatable-Read。

3.2 测试Read Uncommitted

  • 设置数据库隔离级别为Read Uncommitted,在命令行1、命令行2中都执行设置语句:
# 设置隔离级别为READ-UNCOMMITTED
set tx_isolation='READ-UNCOMMITTED';
# 查看隔离级别
select @@tx_isolation;

设置隔离级别并查看

  • 在右边命令行中执行以下语句:
# 开启命令行的事务
start transaction;
  • 在左边命令行中执行以下语句:
# 开启命令行的事务,两个事务产生重合
start transaction;
# 修改ali为zhangli
update t_user set name='zhangli' where id=1;
# 查看t_user表,显然已经改变
select * from t_user;
  • 在右边命令行中执行以下语句:
# 查看t_user表,显然查到了左边命令行中修改但是未提交的数据,这就是脏读
select * from t_user

READ-UNCOMMITTED不能避免脏读

  • 在左边命令行1中执行以下语句:
# 回滚
rollback;
# 查看t_user表,回滚到之前数据
select * from t_user;
  • 在右边命令行中执行以下语句:
# 查看t_user表,也回滚到之前数据
select * from t_user;
# 回滚,关闭事务,恢复到没有事务的状态
rollback;

回滚
由此可见,“READ-UNCOMMITTED”隔离级别使得一个事务可以读取另一个事务没有提交的数据。

3.3 测试Read Committed

  • 设置数据库隔离级别为Read Committed,在命令行1、命令行2中都执行设置语句:
# 设置隔离级别为read-committed
set tx_isolation='read-committed';
# 查看隔离级别
select @@tx_isolation;

设置隔离级别并查看

  • 在右边命令行中执行以下语句:
# 开启命令行2的事务
start transaction;
  • 在左边命令行中执行以下语句:
# 开启命令行的事务,两个事务产生重合
start transaction;
# 修改ali为zhangli
update t_user set name='zhangli' where id=1;
# 查看t_user表,显然已经改变
select * from t_user;
  • 在右边命令行中执行以下语句:
# 查看t_user表,显然还是以前的数据,这就证明了“read-committed”级别不能读取未提交的事务
select * from t_user;

“read-committed”级别不能读取未提交的事务

  • 在左边命令行执行以下语句:
# 提交
commit;
# 查看数据
select * from t_user;
  • 在右边命令行执行以下语句:
# 查看数据,此时看到了新的数据“zhangli”,这就证明了“read-committed”级能读取已提交的事务
select * from t_user
# 回滚,关闭事务,恢复到没有事务的状态
rollback;

“read-committed”级能读取已提交的事务
然而,此时右边命令行是委屈的,它在同一个事务中啥都没干,却查到了两个不同的数据,这就是不可重复读。
出现了幻读
由此可见,“READ-COMMITTED”隔离级别使得一个事务只能读取另一个事务提交的数据,但是不能解决不可重复读。

3.4 测试Repeatable Read

  • 设置数据库隔离级别为Repeatable Read,在命令行1、命令行2中都执行设置语句:
# 设置隔离级别为repeatable-read
set tx_isolation='repeatable-read';
# 查看隔离级别
select @@tx_isolation;

设置隔离级别并查看

  • 在右边命令行中执行以下语句:
# 开启命令行2的事务
start transaction;
  • 在左边命令行中执行以下语句:
# 开启命令行的事务,两个事务产生重合
start transaction;
# 修改ali为zhangli
update t_user set name='xiaoli' where id=1;
# 查看t_user表,显然已经改变
select * from t_user;
  • 在右边命令行中执行以下语句:
# 查看t_user表,当然还是以前的数据,因为"repeatable read"比"read-committed"更为严格,所以更加不能读取未提交的事务
select * from t_user;

不能读取未提交的事务

  • 在左边命令行中执行以下语句:
# 提交
commit;
# 查看
select * from t_user;
  • 在右边命令行中执行以下语句:
# 先查看,还是之前的数据
select * from t_user;
# rollback以关闭事务
rollback;
# 再次查看,才看到了新的数据,这就说明,可重复读解决了不可重复读的问题。
select * from t_user;

可重复读解决了不可重复读的问题
但是,Repeatable Read不能解决幻读的问题,请执行以下语句:

# 在左边命令行执行
start transaction;
# 在右边命令行执行
start transaction;
# 在左边命令行执行
insert into t_user(id,name) values(3,'ali');
commit;
select * from t_user;
# 在右边命令行执行,还是只能看到两行记录
select * from t_user;
commit;
select * from t_user;  # 在我的事务过程中没加入记录,却看到了3行记录,还以为眼花了,幻读了

3.5 测试Serializable

  • 设置数据库隔离级别为Serializable,在命令行1、命令行2中都执行设置语句:
# 设置隔离级别为serializable
set tx_isolation='serializable';
# 查看隔离级别
select @@tx_isolation;

设置隔离级别并查看

  • 在右边命令行中执行以下语句:
# 开启命令行2的事务
start transaction;
  • 在左边命令行中执行以下语句:
start transaction;
insert into t_user(id,name) values(4,'zhangli');# 这时候是执行不下去的,因为可序列化约束了最严格的的隔离级别,事务之间不能重合。
  • 在右边命令行执行以下语句:
commit;# 在提交执行的瞬间,左边的insert可以向下执行,因为事务没有重合了
# 再次查询,还是之前的记录
select * from t_user
  • 在左边命令行执行以下命令:
commit;
# 能看到最新的记录
select * from t_user;
  • 在右边命令行执行以下命令:
# 看到了最新的记录
select * from t_user

可见,序列化约束了最严格的隔离级别,事务不能重合,什么问题都能解决,只是效率最低。
以上就是mysql的四种事务隔离级别的验证。

猜你喜欢

转载自www.cnblogs.com/alichengxuyuan/p/12519891.html