一、事务的基本概念
所谓事务是用户定义的、不可分割的一组操作序列,这些操作只能全做或全都不做,不能存在中间状态。
MySQL数据库,当且仅当引擎是InnoDB,才支持事务;它为我们提供这些与事务相关的语句:
start transaction | begin | set autocommit=0 # 开始事务(这里的3种方式都可以)
commit # 提交当前事务
rollback # 回滚当前事务,取消所有操作
MySQL初始设置会将autocommit(自动提交)设置为1,表示用户对数据库的每个操作都作为一个事务自动提交,仅当使用 start transaction 或 begin 开始一个新事务后,autocommit才会临时失效,直到出现事务结束语句(commit | rollback)。(在事务未结束之前开启另一个新事务会自动commit)
二、事务的四个特性
事务具有4个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),简称ACID特性。
- 原子性: 事务作为数据库的逻辑工作单位,是不可分割的,事务内的操作要么全做,要么全不做。
- 一致性: 事务的执行结果必须使数据库从一个一致性状态转换到另一个一致性状态。一致性是和原子性密切相关的特性,一致性状态的转换必然要经过原子性的操作。若数据库在完成事务时突然发生故障而中断,原子性不能保证,那么数据库内的数据就会出错,处于不一致的状态。
- 隔离性: 事务的执行不能互相干扰,即一个事务内的操作和使用的数据对其他并发事务是隔离的,不可见的。事务将数据库由一个一致性状态转换为另一个一致性状态时,不能出现非本事务内的操作或数据,即不能被其他事务干扰。
- 持久性: 一个事务一旦提交,它对数据库的修改应该是永久性的,不会因接下来的操作或故障影响已提交的事务。
三、事务的并发问题
- 脏读: 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 不可重复读: 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新(
删除,添加
)并提交,导致事务A多次读取同一数据时,结果 不一致。 - 幻读: 并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读(
看后面最后一个测试
)。
四、事务的隔离级别
事务的隔离级别:读未提交(read uncommitted)、读已提交(read committed)、可重复读(repeatable read)、串行化(serializable)。
查看事务的隔离级别:
SELECT @@tx_isolation; -- 查看当前事务的隔离级别,MySQL 默认可重复读(repeatable read)
重新设置MySQL事务隔离级别:
# 设置mysql的隔离级别:
set session transaction isolation level 事务隔离级别
# 设置read uncommitted级别:
set session transaction isolation level read uncommitted;
# 设置read committed级别:
set session transaction isolation level read committed;
# 设置repeatable read级别:
set session transaction isolation level repeatable read;
# 设置serializable级别:
set session transaction isolation level serializable;
&& 当事务的隔离级别是读未提交
(read uncommitted)时,会出现脏读
现象,效果如图:
假设右边的事务A,右边的是事务B
, 事务B第一次查询id=3的学生信息时,age=52,之后事务A更新了这个学生的age值为42,接着事务B有一次查询这个学生的age值为42,最后事务A回滚了,所以这个42并不是数据中的真实数据,所以为脏数据。
&& 当事务的隔离级别是读已提交
(read committed)时,会解决脏读
现象,效果如图:
和上面的操作相同,发现事务B两次查询的结果相同,都是52,所以可以看出读已提交解决了脏读
现象。但是它会出现不可重复读
现象,如下图:
事务B第一次查询id=3的数据,可以正常查询到,然后事务A突然将id=3的记录删除并提交了,紧接着事务B再次查询id=3的那条记录,发现找不到了,这种现象就是不可重复读。
&& 当事务的隔离级别是可重复读
(repeatable read)时,会解决不可重复读
现象,效果如图:
事务B第一次查询id=4的数据,可以正常查询到,然后事务A突然将id=4的记录删除并提交了,紧接着事务B再次查询id=4的那条记录,依然可以查询到这条记录。这说明解决了不可重复读
现象。但是这个隔离级别仍然会出现幻读
现象,效果如下图:
事务B第一次查询id=2的学生时,发现没有这条记录,于是事务A想要添加一条id=2的记录,但是这时事务A添加了一条id=2的记录,因此事务B添加时就显示失败了,于是事务B在一次查询id=2的记录,发现确实是不存在,不存在但是又无法添加,事务B的这种现象就叫做幻读;当然串行化
(serializable)隔离级别可以解决这种现象,但是性能会大大降低,不推荐,也就不在演示了。