1 隔离级别引入
并发访问,可能导致,脏读,不可重复读,幻读问题.
1 并发访问
是指在同一个时间段,有多个用户开启了事务,并且同时访问同一张表中记录,称为事务的并发访问。也就是多个事务在并行的执行。
在理想状态,事务的操作是不存在并发访问问题的. 在实际的使用过程中,因为事务的隔离级别不同,可能导致出现上述三种并发访问问题.
2 并发访问引出问题
并发访问的问题 | 含义 |
---|---|
脏读 | 一个事务读取到了另一个事务没有提交的数据 |
不可重复读 | 正常来说,一个事务多次读取同一条记录结果应该是一致的, 如果出现多次读取不一致的情况,称为不可重复读。通常是 因为一个事务在读取数据,另一个读取更新了这条记录导致。 |
幻读 | 一个事务在统计或查询的时候,2次出现查询的记录数不同。 通常是因为一个事务在统计,另一个事务插入或删除了记录导致。 |
上述三种并发访问问题,可以通过设置事务隔离级别去控制.隔离级别越高,并发出现的问题就越少。
2 四种隔离级别
级别 | 名称 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 数据库默认级别 |
---|---|---|---|---|---|---|
1 | 读未提交 | read uncommitted | √ | √ | √ | |
2 | 读已提交 | read committed | √ | √ | Oracle和Sql Server | |
3 | 可重复读 | repeatable read | √ | Mysql | ||
4 | 串行化 | serializable |
说明:
- 1 Read uncommitted (读未提交): 隔离级别最低,三种并发访问的问题都是存在
- 2 Read committed (读已提交):解决了脏读的问题,Oracle和SQL Server默认是这种隔离级别
- 3 Repeatable read (可重复读):这是MySQL默认的隔离级别,可以解决脏读和不可重复读的问题
- 4 Serializable (串行化):所有的事务都有串行的方式执行,不存在并发的事务
ps:
隔离级别越高:安全性越高,性能就越低
3 案列
命令 | 说明 |
---|---|
select @@tx_isolation | 查询事务隔离级别 |
set global transaction isolation level 隔离级别 | 设置全局事务隔离级别 |
隔离级别:
- read uncommitted
- read committed
- repeatable read
- serializable
1 脏读
一个事务读取到另一个事务未提交的数据,解决方法就是提高事务的隔离级别为read committed.
1 案例说明
1 准备数据
-- 给虹猫和蓝兔金额设置为1000
update account set balance = 1000;
2 操作步骤
1 设置全局的隔离级别为最低
2 开启事务
3 更新账户余额, 虹猫减100 ,蓝兔加100
4 用一个新的命令行查看蓝兔的金额,钱已到账
5 回滚更新账户余额操作
6 用蓝兔命令行查询,钱恢复原样
-- 1 设置隔离级别
set global transaction isolation level read uncommitted;
-- 2 开启事务
start transaction;
-- 3 更新账户余额
update account set balance=balance-100 where name='hm';
update account set balance=balance+100 where name='lt';
-- 4 使用 另新命令行, 切换到自己的库,本人使用test库
use test;
select * from account;
-- 5 回滚
rollback;
-- 6 使用新命令行,查询数据
select * from account;
解决上述问题方法: 将全局的隔离级别进行提升
-- 1 设置隔离级别为 可重复读
set global transaction isolation level read committed;
-- 2 重复上述操作 虹猫账号没有变化
2 不可重复读
一个事务多次读取的数据不同,导致无法判断数据的正确性.
1 设置全局的隔离级别为读已提交
2 开启事务
3 在虹猫命令行查询虹猫余额
4 在新命令行,开启事务,给虹猫加100元钱,提交事务.
5 在虹猫命令行,再次查询虹余额,发现金额增加了100
6 虹猫命令行提交事务
-- 1 设置隔离级别
set global transaction isolation level read committed;
-- 2 虹猫命令行
start transaction;
select * from account where name='hm';
-- 3 新命令行
use test;
start transaction;
update account set balance=balance+100 where name='hm';
commit;
-- 4 虹猫命令行
select * from account where name='hm';
-- 5 虹猫命令行提交事务
commit;
解决方法:将全局的隔离级别进行提升
-- 1 设置隔离级别为 可重复读
set global transaction isolation level repeatable read;
-- 2 重复上述操作 虹猫账号没有变化
3 幻读
一个事务多次统计数据,得到数据条数不同,无法判断数据正确性.
如虹猫金额大于1000,蓝兔金额小于1000. 现在需要统计金额大于1000的人员. 第一个事务查询到的是虹猫, 第二个事务,给蓝兔增加了超过1000的钱,第一个事务再查询时,发现金额大于1000的人员变成两个了.
1 设置全局的隔离级别为可重复读
2 开启事务
3 在虹猫命令行查询余额大于1000的数量
4 在新命令行,开启事务,给蓝兔加1000元钱,提交事务.
5 在虹猫命令行,再次查询余额大于1000的数量,数量变化了
6 虹猫命令行提交事务
-- 1 设置隔离级别
set global transaction isolation level repeatable read;
-- 2 虹猫命令行
start transaction;
select count(id) from account where banlance > 1000;
-- 3 新命令行
use test;
start transaction;
update account set balance=balance+1000 where name='lt';
commit;
-- 4 虹猫命令行
select count(id) from account where banlance > 1000;
-- 5 虹猫命令行提交事务
commit;
解决方法: 提高隔离级别serializable
-- 1 设置隔离级别为 串行化
set global transaction isolation level serializable;
-- 2 重复上述操作 统计数据没有变化