三十二、MySQL基础系列笔记之事务实例演示(下)
上篇 MySQL基础系列笔记之事务基础概念详解 将事务的基本概念做了一个较为详细的基本概念记录,那么此篇将进行实例演示。对事务概念有所模糊,建议先阅读上篇文章。
准备工作-建表
CREATE TABLE `account`(
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '',
`name` VARCHAR(30) NOT NULL COMMENT '姓名',
`salary` DECIMAL(10,2) COMMENT '薪水'
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;
INSERT INTO account VALUES (1,'张三',1000), (2,'李四',2000);
事务使用步骤
为了方便查看,此篇将温故下上篇文章的记录,事务的使用步骤。
# 第一步:关闭自动提交
set autocommit =0;
# 开启事务,[可选]
start transaction;
# 第二步:设置事务隔离级别
set session transaction isolation level Read Uncommitted;
# 第三步:sql语句
# 第四步:COMMIT或ROOLBACK
事务实例演示
准备工作:打开2个PowerShell黑窗口,分别连接上mysql。第一个黑窗口为A,第2个为B。
读未提交(Read Uncommitted)
步骤一:A、B窗口,关闭事务自动提交
set autocommit =0;
步骤二:A、B窗口设置事务隔离级别(两个一样)
# 读未提交
set session transaction isolation level Read Uncommitted;
步骤三:A窗口向表中插入一条数据
insert into account values (3,'lucy',3000);
注意:A窗口插入一条数据后,不要提交事务,不要提交事务,不要提交事务!A插入一条数据,立即到B窗口中查看数据。
步骤四:B窗口中查看数据
mysql> select * from account;
+----+--------+---------+
| id | name | salary |
+----+--------+---------+
| 1 | 张三 | 1000.00 |
| 2 | 李四 | 2000.00 |
| 3 | lucy | 3000.00 |
+----+--------+---------+
3 rows in set (0.00 sec)
A窗口并未提交事务,此时B窗口中却查看到了A事务中插入的一条数据。
步骤五:A窗口ROLLBACK事务
ROLLBACK;
步骤六:B窗口查看数据
mysql> select * from account;
+----+--------+---------+
| id | name | salary |
+----+--------+---------+
| 1 | 张三 | 1000.00 |
| 2 | 李四 | 2000.00 |
+----+--------+---------+
当A窗口回滚事务之后,B窗口再次查看却发现那条数据神奇的消失了。
可重复读(Repeatable Read)
步骤一:A、B窗口,关闭事务自动提交
set autocommit =0;
步骤二:A、B窗口设置事务隔离级别(两个一样)
# 隔离级别为可以重复读
set session transaction isolation level Repeatable Read;
步骤三:A窗口向表中插入一条数据
insert into account values (3,'lucy',3000);
# 注意:不要提交事务
步骤四:B窗口中查询数据
mysql> select * from account;
+----+--------+---------+
| id | name | salary |
+----+--------+---------+
| 1 | 张三 | 1000.00 |
| 2 | 李四 | 2000.00 |
+----+--------+---------+
2 rows in set (0.00 sec)
A窗口中插入了一条数据,此时B窗口查询数据并没有查看到A窗口插入的那一条数据。该隔离级别避免了脏读与不可重复读。
步骤五:A窗口提交事务
COMMIT;
步骤六:B窗口再次查看数据
mysql> select * from account;
+----+--------+---------+
| id | name | salary |
+----+--------+---------+
| 1 | 张三 | 1000.00 |
| 2 | 李四 | 2000.00 |
+----+--------+---------+
2 rows in set (0.00 sec)
A窗口提交了事务,由于B窗口没有提交事务,因此看到的还是之前的数据。
步骤七:B窗口提交事务,然后再查看
# B窗口提交事务
COMMIT;
# B窗口查看数据
mysql> select * from account;
+----+--------+---------+
| id | name | salary |
+----+--------+---------+
...此处省略前面的数据
| 3 | lucy | 3000.00 |
+----+--------+---------+
3 rows in set (0.00 sec)
读已提交(Read Committed)
步骤一:A、B窗口,关闭事务自动提交
set autocommit =0;
步骤二:A、B窗口设置事务隔离级别(两个一样)
# 读已提交
set session transaction isolation level read committed;
步骤三:A窗口中插入一条数据
insert into account values(4,'lily',4000);
步骤四:B窗口查看数据
mysql> select * from account;
+----+--------+---------+
| id | name | salary |
+----+--------+---------+
...
| 3 | lucy | 3000.00 |
+----+--------+---------+
3 rows in set (0.00 sec)
还是之前的3条数据。避免了脏读。
步骤五:A窗口提交事务
COMMIT;
步骤六:B窗口查看数据并提交事务
mysql> select * from account;
+----+--------+---------+
| id | name | salary |
+----+--------+---------+
....
| 4 | lily | 4000.00 |
+----+--------+---------+
4 rows in set (0.00 sec)
# 提交事务
COMMIT;
# 再次查看数据,发现仍旧是4条数据
可以清晰的看到,步骤四、六查询的结果不一致,这就是不可重复读。
串行(Serializable)
步骤一:A、B窗口,关闭事务自动提交
set autocommit =0;
步骤二:A、B窗口设置事务隔离级别(两个一样)
# 串行
set session transaction isolation level serializable;
步骤三:A窗口修改一条数据
update account set name='大明' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
# 注意:此时可以看到修改成功,但实际上此时没有修改成功
可以看到A窗口事务处于阻塞状态,它在等待B窗口提交事务。
步骤四:B窗口插入一条数据
insert into account values (5,'小毛',100);
# 注意:此时B窗口事务处于阻塞状态
步骤五:A窗口提交事务并查看数据
COMMIT;
# 此时B窗口才插入成功
# A窗口查看,发现处于阻塞状态
select * from account;
步骤六:B窗口提交事务
COMMIT;
# B窗口提交事务之后,A窗口才看到了数据。
SERIALIZABLE会让并发的事务串行执行(多个事务之间读写、写读、写写会产生互斥,效果就是串行执行,多个事务之间的读读不会产生互斥)。
读写互斥:事务A中先读取操作,事务B发起写入操作,事务A中的读取会导致事务B中的写入处于等待状态,直到A事务完成为止。
表示我开启一个事务,为了保证事务中不会出现上面说的问题(脏读、不可重复读、读已提交、幻读),那么我读取的时候,其他事务有修改数据的操作需要排队等待,等待我读取完成之后,他们才可以继续。
写读、写写也是互斥的,读写互斥类似。
2020-11-22