一、事务(transaction)
1、什么是事务?
一个事务是一个完整的业务逻辑单元
只有DML语句才支持事务(才和事务有关系,insert update delete)
2、事务的ACID特性:
- 原子性:要么都发生,要么都不发生。
- 一致性:从一个一致性状态,变换到另一个一致性状态。
- 隔离性:各个事务不会干扰。
-
3、提交 commit 回滚 rollback
Rollback:回滚到上一次的提交点
-
4、事务的并发问题
发生条件:多个事务同时操作同一个数据库的相同数据时
脏读
一个事务读取了其他事务还没有提交的数据,只是读到的是其他事务”插入“的数据
- 不可重复读
一个事务多次读取,结果不一样
- 幻读
读到的数据有可能是别的事务已经删除的数据
设置隔离级别来解决并发问题
5、隔离级别
理论上隔离级别包括四个(所有的都是二档起步 MySQL3档):
- 读未提交(read uncommitted)【对方事务没有提交的数据,我们能读到】
- 脏读:读到了脏数据
- 读已提交(read committed)【对方事务提交后的数据我们能读到】
- 不可重复读:一个事务多次读取,结果不一样 解决了脏读
- 可重复读(repeatable read)【MySQL默认】
- 幻读:别的事务把数据删了,但是我这可以读到。【解决了不可重复读问题 ,两次读的都是一致的】
- 序列化读/串行化读(serializable)
- 解决了所有问题,但是效率低,需要事务排队执行
1) 演示事务隔离性
:::info
mysql的事务是自动提交的,(也就是说只要执行一条DML语句,则自动提交一次)
关闭事务自动提交:start transaction[标志着开启一次事务]
如果一次事务完成后,开启第二次事务需要再次写一遍 start transaction
:::
**
演示开启事务,提交回滚:
首先先创建一张表
Drop table if exists t_user;
Create table t_user(
Id int primary key auto_increment,
Username varchar(255)
);
**Start transaction**
【开启事务标志** **没开启一次事务都要来一遍Start transaction】
Insert into t_user(username) values('zhangsan');
Select * from t_user;
+----+----------+
| Id | Username |
+----+----------+
| 1 | zhangsan |
+----+----------+
Rollback; #回滚
Select * from t_user;
Empty set (0.00 sec)
Insert into t_user(username) values('lisi');
Commit; # 提交
2) 演示读未提交(别人没提交的事务,我能读到)
首先在开启一个cmd窗口(使用同一个root账户即可)
设置全局事务隔离级别
Set global transaction isolation level read uncommitted;
查看事务隔离级别
select @@global.tx_isolation;
把两个窗口的事务隔离级别都设置完成后,exit退出一下,在重新登录
然后都同时开启事务 start transaction
窗口一执行 insert into t_user(username) values('zhangsan'); 【没有commit;】
【脏读】窗口二执行 select * from t_user; (能查到窗口一没有commit的数据‘zhangsan’)
3) 演示读已提交(别人提交的我能读到,导致了两次读的结果一样)
设置全局事务隔离级别
Set global transaction isolation level read uncommitted;
退出 exit
Use test
第一个cmd:
第一次开启事务
Start transaction;
Insert into t_user(username) values('smith');
Commit;
第二次开启事务
Start transaction;
Insert into t_user(username) values('------');
Commit;
第二个cmd
开启事务
Start transaction;
Select * from t_user;查到了提交的SMITH
等第二个事务提交
Select * from t_user; 查到了提交的'--------'
两次查询的结果不一样【不可重复度】
4) 演示可重复读
设置隔离级别
Set global transaction isolation level repeatable read;
exit退出
Use test
第一个cmd
Start transaction
Truncate t_user; #把表里面的内容全删掉了,此时里面是空的
第二个cmd
Start transaction; #和第一个cmd同时开启
Select * from t_user; #读到了数据,并不是空的【幻读,读到的数据是虚幻数据】
5) 演示序列化读
设置隔离级别
Set global transaction isolation level serializable;
退出 exit
登录 use test
第一个cmd
Start transaction
Insert into t_user values('SMITH'); # 此时没有commit 第二个窗口的查询不会执行,等到commit之后才会执行
Commit #此时 第二个cmd才会执行select语句
第二个cmd
Start transaction
Select * from t_user; 【排队依次等待执行】