事务及隔离级别

事务四大特性

据库具有 ACID四个特性,分别指:

Atomicity - 原子性

原子操作不可分割,内部要么全部成功,要么全部失败。

Consistency - 一致性

系统从一个一致状态转换到另一个一致状态。事务的一致性决定了一个系统设计和实现的复杂度。事务可以不同程度的一致性,下面会详细提到。

Isolation - 隔离性

事务不被其他事务干扰,相互隔离。 每个事务都感觉不到其他事务在执行,下面为详细提到事务的隔离的级别。

Durability - 持久性

事务一旦提交,那么数据的改变就是永久性的。

事务一致性

此处主要参考: 理解事务——原子性、一致性、隔离性和持久性

  • 强一致性:读操作可以立即读到提交的更新操作。
  • 弱一致性: 提交的更新操作,不一定立即会被操作读取到,此种情况会存在一个不一致窗口,指的是读操作可以读到最新值的一段时间。
  • 最终一致性: 是弱一致性的特例。事务更新一份数据,最终一致性保证在没有其他事务更新同样值的话,最终所有的事务都会读到之前事务更新的最新值。如果没有错误发生,不一致窗口的大小依赖于:通信延迟,系统负载等。
  • 单调一致性: 如果一个进程已经读到一个值,那么后续不会读到更早的值。
  • 会话一致性: 保证客户端和服务器交互的会话过程中,读操作可以读到更新操作后的最新值。

事务隔离性

如果不考虑隔离性,在事务并发操作时,可能出现的问题有:

  • 脏读一个事务读取了另一个事务未提交的数据

    例如:公司发工资了,领导把5000元打到singo的账号上,但是该事务并未提交,而singo正好去查看账户,发现工资已经到账,是5000元整,非常高 兴。可是不幸的是,领导发现发给singo的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,最后singo实际的工资只有 2000元,singo空欢喜一场。

  • 不可重复读一个事务内,单份数据多次读取结果不同,这是由于读取间隔,被别的事务修改并提交了 (事务内重复读取会有问题,不重复读则没问题,则理解为不可重复读问题)

    例如:singo拿着工资卡去消费,系统读取到卡里确实有2000元,而此时她的老婆也正好在网上转账,把singo工资卡的2000元转到另一账户,并在 singo之前提交了事务,当singo扣款时,系统检查到singo的工资卡已经没有钱,扣款失败,singo十分纳闷,明明卡里有钱,为 何……

  • 幻读一个事务内,多次读取数据的结果集合不同,幻读是由于读取间隔,被别的事务插入了数据

    例如:singo的老婆工作在银行部门,她时常通过银行内部系统查看singo的信用卡消费记录。有一天,她正在查询到singo当月信用卡的总消费金额 (select sum(amount) from transaction where month = 本月)为80元,而singo此时正好在外面胡吃海塞后在收银台买单,消费1000元,即新增了一条1000元的消费记录(insert transaction … ),并提交了事务,随后singo的老婆将singo当月信用卡消费的明细打印到A4纸上,却发现消费总额为1080元,singo的老婆很诧异,以为出 现了幻觉,幻读就这样产生了

针对上面的问题,一般定义有以下几种事务隔离级别:

  • READ UNCOMMITED (可以读取到未提交的数据)一个事务可以读到另一个事务未提交的结果,以上的脏读不可重复读幻读问题都可能会发生。
  • READ COMMITED (可以读取到已提交的数据)只有在事务提交后,其更新结果才会被其他事务看见。可以解决上面的脏读问题
  • Repeated Read (重复读取)在同一个事务中,对于同一份数据的读取结果总是相同的,无论其他事务对这份数据是否进行操作,以及整个事务是否提交。可以解决脏读、不可重复读问题
  • Serializable (串行化) 隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题

大多数数据库的默认级别就是Read committed,如OracleSQL Server;

注:MySQL 的默认隔离级别是REPEATABLE-READ,查看命令select @@tx_isolation;

例子参考:

数据库事务隔离级别

数据库事务的四大特性以及事务的隔离级别

理解事务——原子性、一致性、隔离性和持久性