一、mysql中事务特性以及隔离机制(选做)
ACID
脏读,不可重复读,幻读
不同隔离级别解决什么问题(实际操作验证)
①脏读
1.创建数据库test以及表rooms
2.先开一个mysql客户端(也可以说是命令行),使用use test;启用test数据库,再使用set session transaction isolation level read COMMITTED;
3.使用这个数据库,再设置事务的隔离级别为读未提交,最后使用select语句进行一次查询操作,方便后面的对照
(1)使用这个数据库
use test;
(2)设置事务的隔离级别
set session transaction isolation level read UNCOMMITTED;
查看数据库的隔离级别
select @@transaction_isolation;
结果:
创建表格rooms:
create table rooms(
id int(3) not null,
tenant_id int(3) default null,
rent int(5) default null,
primary key(id) using btree
)engine = InnoDB character set =latin1 collate = latin1_swedish_ci row_format =dynamic;
向表格rooms中插入数据:
insert into rooms values (120,1,1000);
insert into rooms values (123,2,222);
4.开启另一个mysql命令行,尝试更新一下数据(但不提交,如果要提交 最后一行加入 commit指令)
begin; // 这个语句开启一个事务
update rooms set id = 1 where id = 120;
在update所在的事务没有提交(使用commit指令提交)的情况下使用select语句
select * from rooms
结果(因为事务的隔离级别为 读未提交 ,所以读取到了update事务未提交的内容):
②不可重复读:
在继续沿用rooms表的情况下,
1.先开一个mysql客户端(也可以说是命令行),使用use test;启用test数据库,再使用set session transaction isolation level read COMMITTED; 命令设置数据库事务的隔离级
别为 读已提交(因为数据库的默认隔离级别为可重复读)
2.开启事务,使用start transaction;或者begin;命令
3.使用select * from rooms; 查询数据库中的数据
查询结果如下:
4.接着再开一个命令行,使用 update rooms set rent = 1100 where id = 120; 将房间号为120的房租改为1100;注意这个命令行中,我们不用设置手动开启或者关闭一个事务,mysql默认会为我们提交这个更新事务。
update rooms set rent = 1100 where id = 120;
5.在第一个命令行中,使用select * from rooms; 查询数据库中的数据(注意这个时刻,第一个命令行中的事务还处于待提交状态,因为没有使用commit;命令)。
select *from rooms;
查询结果:查询到了update事务提交后的数据,由此造成了不可重复读的问题
③幻读:
1.开启第一个mysql客户端,启用test数据库,使用数据库默认的隔离级别(可重复读)。代码如下:
begin;
set session transaction isolation level read COMMITTED;
update rooms set rent = 1188 where id = 120;
2.在第一个客户端中使用begin;命令开启事务,并且执行select * from rooms; 操作,但不提交
结果如下
![](https://i-blog.csdnimg.cn/blog_migrate/93800064d5dfb543d7a87c6eea186f5e.png)
3.开启第二个mysql客户端,在第二个客户端中执行insert into rooms (id, tenant_id, rent) values (124, 5, 600);语句
4.在第一个客户端中 再次执行 select * from rooms; 操作,查到的结果和第2步中的一样,因为在 "可重复读"的隔离级别下,使用的是快照读,读取的都是第一次select的数据
![](https://i-blog.csdnimg.cn/blog_migrate/93800064d5dfb543d7a87c6eea186f5e.png)
5.这里如果我们把快照读改为当前读,即执行select * from rooms for update;每次读取的都是最近更新的数据
![](https://i-blog.csdnimg.cn/blog_migrate/081e7eeee86b68d6bff9de61f34c80db.png)
6.即便此时我们不使用当前读,而使用快照读,直接执行更新操作,更新sql会将符合条件的由其他事务提交的最新数据都会更新,这也是幻读带来的影响(因为更新事务会先扫描全表查询数据,然后将得到的数据拿回内存,对内存中的数据进行修改)
(1)在快照读的情况下执行更新操作
update rooms set rent = rent - 200 where rent > 200 and id < 125;
(2)执行快照读select 操作
select *from rooms;