先来复习一下事务的四大特性:
- 原子性(Atomicity):事务是不可分割的最小操作单位,事务中的所有操作要么全部执行成功,要么全部失败回滚,不能只执行其中一部分操作。
- 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏,数据总是从一个一致性状态转移到另一个一致性状态。例如,如果一个事务要求将某个账户的金额从 A 转移到 B,那么无论事务是否成功,最终账户 A 和账户 B 的总金额应该保持不变。
- 隔离性(Isolation):事务之间是相互隔离的,事务可以在不受外部并发操作的影响的独立环境下运行。
- 持久性(Durability):事务完成后(进行提交或者回滚操作),对数据库的修改将永久保存在数据库中,即使系统故障也不会丢失。因为数据库最终的数据是存储到磁盘上的。
并发事务产生的问题
:通俗一点就是两个事务在操作同一个数据库或者是同一张表时所引发的问题。
大致分为以下三种,脏读,不可重复读,幻读。
|-------|------------------------------------------------------|
| 问题 | 描述 |
| 脏读 | 一个事务读到另一个事务还没提交的数据。 |
| 不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。 |
| 幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现"幻觉" |
脏读
上图中事务A内部会执行三次任务(三次完成后事务A才会进行提交操作),事务A先执行了任务1(查询id为1的数据),任务2(修改id为1的数据)。事务A在执行完任务2后,事务B紧接着进行了查询id为1的操作,这时查询的数据是事务A为提交之前的数据,这个数据就是"脏"的,简称脏读。
不可重复读
在事务A第一次进行查询id为1的数据的时候,查询到了结果集1,然后在事务A再次执行查询id为1的数据的之前,事务B对id为1的数据进行了修改,并提交了事务B。这时候事务A再次查询id为1的数据时候就查询出了结果集2,两次结果集不同,这就是不可重复读。
幻读
事务的隔离级别
查看事务的隔离级别:
sql
mysql> select @@Transaction_isolation;
+-------------------------+
| @@Transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
设置当前会话的隔离级别:
sql
SET session TRANSACTION ISOLATION LEVEL 隔离级别;
如果是想在某个事务中设置隔离级别而不想影响别的事务和会话的话可以不用加session:
sql
SET TRANSACTION ISOLATION LEVEL 隔离级别;
先来看下这组区别。以下就这组区别分别进行对比操作:
读未提交(read uncommitted)
读未提交 相比 读已提交 存在脏读问题:
脏读演示:
读已提交(read committed)
读已提交 相比 可重复读 存在不可重复读问题,但是解决了脏读问题:
解决脏读问题演示:
不可重复读演示:
可重复读(repeatable-read)(默认)
可重复读 相比 串行化 存在幻读的问题,但是解决了不可重复读的问题:
解决不可重复读问题展示:
存在幻读:
串行化(serializable)
小结
MySQL 中的事务隔离级别,主要有读未提交、读已提交、可重复度和串行化。这些隔离级别与问题的对应关系如下:
其中,读未提交的性能是最高的,但是安全性和隔离性是最差的,
而串行化则相反,安全性和隔离性最高,但是性能最低。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read uncommitted) | √ | √ | √ |
读已提交(read committed) | × | √ | √ |
可重复读(repeatable-read)(默认) | × | × | √ |
串行化(serializable) | × | × | × |