目录
前言
一、并发事务问题
1.赃读
2.不可重复读
3.幻读
二、事务隔离级别
1.相关操作
2.案例演示
前言
本期我们继续上一期事务的内容,本期的主要讲解的是并发事务的相关问题以及解决方式,内容可能会比较难去理解,不过我会尽量详细说明的。下面看正文。
一、并发事务问题
1.赃读
赃读:一个事务读到另外一个事务还没有提交的数据。
比如B读取到了A未提交的数据。下面看个案例:
# 左窗口SQL语句内容
# 设置隔离级别
set transaction isolation level read uncommitted ;
begin ;
#第一次查询结果
select * from account;
#右边窗口更新了数据后查看结果
select * from account;
# 右边窗口提交事务后查看结果
select * from account;
# 右窗口内容
begin ;
update account set money=money-1000 where name='张三';
commit;
通过上面这个案例可以看出左边事务可以读取到右边事务的提交后的结果,这就出现了读取混乱的情况,毕竟另一个并发事务还没有提交,这里就读取到了数据的变化,这就是脏读。
2.不可重复读
不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。
# 左窗口SQL语句内容
# 设置事务隔离级别
set transaction isolation level read committed ;
#第一次查询结果
select * from account;
#右边窗口更新了数据后查看结果
select * from account;
# 右边窗口提交事务后查看结果
select * from account;
# 右窗口内容
begin ;
update account set money=money+1000 where name='张三';
commit;
3.幻读
幻读:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了 " 幻影 " 。
案例如下:
# 左窗口SQL语句内容
# 设置事务隔离级别
set transaction isolation level Repeatable Read ;
#第一次查询结果
select * from account;
# 右边窗口提交事务后插入新的数据
insert into account(id, name, money) values (3,'老六',3000);
# 左边窗口插入失败后再次查询
select * from account;
# 右窗口内容
begin ;
insert into account(id, name, money) values (3,'王五',3000);
commit;
二、事务隔离级别
为了解决并发事务所引发的问题,在数据库中引入了事务隔离级别。主要有以下几种:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable Read(默认) | × | × | √ |
Serializable | × | × | × |
1.相关操作
查看事务隔离级别SELECT @@TRANSACTION_ISOLATION;
设置事务隔离级别SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
2.案例演示
(1)解决脏读问题:
很简单我们只需要把事务隔离级别换成除了Read uncommitted 的其他三个就行了,示例如下:
这里我们可以看出,当右边事务窗口数据更新后就不会读取到右边窗口的数据了,这里就解决了脏读问题。SQL语句如下:
# 左窗口SQL语句内容
# 设置事务隔离级别
set transaction isolation level read committed ;
#第一次查询结果
select * from account;
#右边窗口更新了数据后查看结果
select * from account;
# 右边窗口提交事务后查看结果
select * from account;
# 右窗口内容
begin ;
update account set money=money-1000 where name='张三';
commit;
(2)解决不可重复读问题
我们只需要把事务隔离级别换成Repeatable Read(默认)就行了,示例如下:
这里我们可以看出,当右边事务窗口修改了数据并且提交了,但是左边窗口读取到的数据并没有发生任何变化,也就是事务不可重复读取,保证一个事务下读取到的结果不会受其他事务的影响,除非当前事务提交后,再次读取,数据结果才会发生变化。
# 左窗口SQL语句内容
# 设置事务隔离级别
set transaction isolation level Repeatable Read ;
#第一次查询结果
select * from account;
#右边窗口更新了数据后查看结果
select * from account;
# 右边窗口提交事务后查看结果
select * from account;
# 左边窗口提交后数据结果
select * from account;
# 右窗口内容
begin ;
update account set money=money+1000 where name='张三';
commit;
(3)解决幻读问题:
我们只需要把事务隔离级别换成Serializable就行了,示例如下:
这里我们可以看出,当左边窗口提交事务之前,右边窗口插入数据是没有反应的,只有当左边窗口提交事务之后,右边窗口才会抛出一个错误(如果等待时间过长也会抛出错误),这就是避免出现幻读的情况,保证事务的完整性。SQL语句如下:
# 设置事务隔离级别
set transaction isolation level Serializable ;
#第一次查询结果
select * from account where id=4;
# 右边窗口没有反应后插入新的数据
insert into account(id, name, money) values (4,'老六',3000);
# 再次查询
select * from account where id=4;
# 右边窗口无反应后提交
commit ;
# 右窗口内容
begin ;
insert into account(id, name, money) values (4,'老马',3000);
# 无反应
以上就是本期的全部内容,我们下次见!
分享一张壁纸: