Mysql隔离级别

Mysql隔离级别

其实以前对隔离级别的概念不是很清除,但是在学习spring事务的时候就更加迷惑了,所有就准备系统的复习一下mysql隔离级别

环境sql

懒的建表,用的是mybatis-plus的demo 加了一个钱的字段

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(30) DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `money` bigint(20) DEFAULT NULL COMMENT '钱财',
  `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  `is_delete` int(11) DEFAULT 0 COMMENT '是否删除',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4;

INSERT INTO `mk_base`.`user` (`id`, `name`, `age`, `money`, `email`, `is_delete`) VALUES (1, 'zhangsan', 18, 100, 'test1@baomidou.com', 0);
INSERT INTO `mk_base`.`user` (`id`, `name`, `age`, `money`, `email`, `is_delete`) VALUES (2, 'lisi', 20, 100, 'test2@baomidou.com', 0);
INSERT INTO `mk_base`.`user` (`id`, `name`, `age`, `money`, `email`, `is_delete`) VALUES (3, 'Tom', 28, 100, 'test3@baomidou.com', 0);
INSERT INTO `mk_base`.`user` (`id`, `name`, `age`, `money`, `email`, `is_delete`) VALUES (4, 'Sandy', 21, 100, 'test4@baomidou.com', 0);
INSERT INTO `mk_base`.`user` (`id`, `name`, `age`, `money`, `email`, `is_delete`) VALUES (5, 'Billie', 24, 100, 'test5@baomidou.com', 0);

四种隔离等级

read-uncommitted 读未提交

read-committed 读已提交

repeatable-read 可重复读

serializable 序列化

查看默认的隔离级别

# 查询默认的隔离级别  REPEATABLE-READ 可重复度
SELECT @@global.tx_isolation;  
# 查看当前绘画的隔离级别
SELECT @@tx_isolation
# 修改隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE

Serializable

改一下隔离级别

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE

我们运行前2句sql,启动一个事务但是不要提交;

START TRANSACTION;
UPDATE `user` set money = 99 WHERE `name` = "zhangsan";
# 这里先不执行
COMMIT;

我们在启动一个事务去提交,这里都运行 将张三的钱更改成1块钱

START TRANSACTION;
UPDATE `user` set money = 1 WHERE `name` = "zhangsan";
COMMIT;

我们可以看见第二个事务会一直卡住,它会等待第一个事务结束后才会执行

知道我们的事务超时,或者是上一个事务提交了

结论

很明显 最安全但是最慢

repeatable-read 可重复读

改一下隔离级别

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ

我们启动一个事务去查询张三的钱 不要提交事务

START TRANSACTION;
SELECT * FROM `user` WHERE  `name` = "zhangsan";
# 这里我们先不要提交
COMMIT;

我们可以看见为100元, 我们用另一个事务将钱改成1000元

START TRANSACTION;
UPDATE `user` set money = 1000 WHERE `name` = "zhangsan";
COMMIT;

我们可以看见钱已经被我们改成1000元了,但是在之前没有提交的事务中查询,我们查到的还是100元

直到事务提交后,才能查到最新的值

结论

​ 在同一事务中同一sql查询到的值是相同的

这个隔离级别 会产生幻读的问题

模拟一个业务场景

​ 我们需要查询用户名zhangsan是否存在,如果存在则删除张三,

这个时候我们启动一个事务去查询zhangsan,查询到准备删除,这个时候第二个事务把张三删除了,第二个事务提交了,导致第一个事务删除的时候报错了,这就是幻读.

在模拟一个业务场景

​ 我们需要查询用户名zhangsan是否存在,如果不存在则创建张三,

这个时候我们启动一个事务去查询zhangsan,没查询到准备添加,这个时候第二个事务添加了张三,第二个事务提交了,然后第一事务也提交了,导致目前数据库中就有2个为zhangsan 的用户了,登陆时就会有问题;

但是一般账号都会设置为唯一索引,所以第一个事务就会抛出异常.这就是幻读,

read-committed

改一下隔离级别

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED

结论

​ 在同一事务中,同样的sql读取的数据不同,可以读取到其他事务已经提交的数据

存在不可重复读,和幻读的问题

read-uncommitted

改一下隔离级别

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

结论

会读取到其他事务没有提交的数据

会出现 脏读,不可重复读,和幻读

posted @ 2022-01-10 16:04  immortal_mode  阅读(33)  评论(0编辑  收藏  举报