事务是什么?
事务就是要保证一组数据库操作,要么全部成功,要么全部失败。
事务的四个特性是什么?
事务的四个特性包括:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolcation)和持久性(Durability),简称ACID。
事务的隔离级别是什么?
当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。
什么是脏读、不可重复读和幻读?
-
脏读(读取未提交数据),比如,A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。
-
不可重复读(前后多次读取,数据内容不一致),比如,事务A在执行读取操作,由整个事务A比较大,前后读取同一条数据需要经历很长的时间 。而在事务A第一次读取数据,比如,此时读取了小明的年龄为20岁,事务B执行更改操作,将小明的年龄更改为30岁,此时事务A第二次读取到小明的年龄时,发现其年龄是30岁,和之前的数据不一样了,也就是数据不重复了,系统不可以读取到重复的数据,成为不可重复读。
-
幻读(前后多次读取,数据总量不一致),比如事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,成为幻读。
事务的隔离级别有哪些?
SQL 标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和可串行化(serializable )
-
读未提交,是指一个事务还没提交时,它做的变更就能被别的事务看到;最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读;
-
读提交,是指一个事务提交之后,它做的变更才会被其他事务看到;允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生;
-
可重复读,是指一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的;当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的;对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生;
-
可串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行;可串行化是最高的隔离级别,所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
| 隔离级别 | 脏读 | 不可重复读 | 幻影读 |
|---|---|---|---|
| read uncommited | √ | √ | √ |
| read commited | × | √ | √ |
| repeatable read | × | × | √ |
| serializable | × | × | × |
能否举例说明四个隔离级别的区别?
假设数据表 T 中只有一列,其中一行的值为 1,下面是按照时间顺序执行两个事务的行为:
| 事务A | 事务B |
|---|---|
| 启动事务,查询得到值1 | 启动事务 |
| 查询得到值1 | |
| 将1改成2 | |
| 查询得到值V1 | |
| 提交事务B | |
| 查询得到值V2 | |
| 提交事务A | |
| 查询得到值V3 |
在不同的隔离级别下,事务 A 会有哪些不同的返回结果,也就是图里面 V1、V2、V3 的返回值分别是什么?
-
若隔离级别是“读未提交”, 则 V1 的值就是 2。这时候事务 B 虽然还没有提交,但是结果已经被 A 看到了。因此,V2、V3 也都是2;
-
若隔离级别是“读提交”,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以, V3 的值也是2;
-
若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的;
-
若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是2。
在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。
什么时候需要“可重复读”的场景呢?
数据校对逻辑的案例。假设你在管理一个个人银行账户表。一个表存了账户余额,一个表存了账单明细。到了月底你要做数据校对,也就是判断上个月的余额和当前余额的差额,是否与本月的账单明细一致。你一定希望在校对过程中,即使有用户发生了一笔新的交易,也不影响你的校对结果。
有关的
-
在MySQL中,事务支持是在引擎层实现的。
-
MySQL 是一个支持多引擎的系统,但并不是所有的引擎都支持事务。比如 MySQL 原生的 MyISAM 引擎就不支持事务,这也是 MyISAM 被 InnoDB 取代的重要原因之一。
-
Oracle 数据库的默认隔离级别其实就是“读提交”;MySQL InnoDB 存储引擎的默认支持的隔离级别是“可重复读”。