快速理解数据库事务隔离级别

1,134 阅读6分钟

事务简介

相信用过MySQL的朋友都知道事务,我们也常常通过这个例子来讲解事务的作用:A向B转账,这里可以分为两步操作数据库,A账户余额减少,B账户余额增加。但是,如果在A账户余额减少的时候突然出现了数据库宕机了等情况,是不是会出现A的余额变少了,但是B的余额却没有增加的情况呢?答案是否定的。原因就是数据库支持事务(常用的关系型数据,如MySQL、Oracle等)。

事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。

事务的结束有两种,当事务中的所以步骤全部成功执行时,事务提交。如果其中一个步骤失败,将发生回滚操作,撤消撤消之前到事务开始时的所以操作。

事务的ACID特性

这个是一个老生常谈的问题,面试中也经常会问:事务的ACID特性分别是什么?这里的ACID分别代表四个单词:原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )。

1 、原子性。事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做

2 、一致性。事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。

3 、隔离性。一个事务的执行不能受其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

4 、持续性。也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。

事务的隔离级别

说事务隔离级别之前,先看看如下问题:

1、脏读(Dirty Read)

所谓脏读是指一个事务中访问到了另外一个事务未提交的数据。如A事务对一条数据进行了修改,但是事务还没提交,此时B事务读到了A事务修改了但是未提交的数据,这就是脏读。

2、不可重复读(Non-repeatable read)

是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两 次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不 可重复读。

3、幻读(Phantom Read)

所谓幻读是指同一个事务内多次查询返回的结果集不一样(比如增加了或者减少了行记录)。比如同一个事务A内第一次查询时候有n条记录,但是第二次同等条件下查询却又n+1条记录,这就好像产生了幻觉,为啥两次结果不一样那。其实和不可重复读一样,发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据。不同在于不可重复读是同一个记录的数据内容被修改了,幻读是数据行记录变多了或者少了

了解了如上几个问题之后,我们再来看看四种事务隔离级别。

1、Read Uncommitted(读取未提交内容)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读。

2、Read Committed(读取提交内容)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这就是所谓的不可重复读(Non-repeatable read)。

3、Repeatable Read(可重读)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

4、Serializable(串行化)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

四种隔离级别可能出现的问题总结

除了性能最差的Serializable(串行化)隔离级别不会出现脏读、不可重复读、幻读问题之外,其他的隔离级别都存在一个或多个问题。不过MySQL的InnoDB引擎通过MVCC的方式解决了Repeatable Read的幻读问题。

事务隔离级别

查看隔离级别

# 查看当前连接的隔离级别
SELECT @@session.tx_isolation;
# 查看全局的事务隔离级别
SELECT @@global.tx_isolation;

设置事务隔离级别

1、全局修改

在mysql的配置文件上修改,如windows的mysql.ini,Linux为my.cnf。

#可选参数有:READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE.
[mysqld]
transaction-isolation = REPEATABLE-READ

2、通过命令对当前连接设置

# 可选参数为:read uncommitted、read committed、repeatable read、serializable
set session transaction isolation level xxx