# 事务

数据库事务(transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

# 四个特性

# 原子性(Atomicity)

原子性是指事务中一个不可再分割的工作单元,事务中的操作要么全部执行,要么全部不执行。要么全部提交成功,要么全部失败回滚。即对于一个事务来说,不能只执行其中的一部分操作。

# 一致性(Consistency)

一致性是指在事务开始之前和事务结束之后,数据库的完整性约束都没有遭到破坏。数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。

比如A给B转账,不论转账是否成功,A和B两人的存款总额是不会发生变化的。

# 隔离性(Isolation)

当多个事务同时并发访问时,事务之间是隔离的,一个事务不应该影响其它事务的运行结果

# 持久性(Durability)

该事务对数据库所做的更改持久地保存在数据库之中,并不会发生回滚。即完成的事务是永久的部分,对系统的影响是永久存在的。

# 事务隔离级别

数据库定义了四个隔离级别:

  • Serializable(序列化):Serializable是最高的事务隔离级别,花销也最高,性能很低,一般很少使用。在该级别下,事务顺序执行,可以避免脏读、不可重复读和幻读。
  • Repeatable read(重复读):可以避免不可重复读,但有可能出现脏读和幻读。例如,只要事务开始,就不能再对该记录进行修改,所以会发生不可重复读。(MySQL默认隔离级别就是Repeatable read)
  • Read committed(读提交):避免了脏读,但是有可能会发生不可重复读和幻读。(SQL Server和Oracle的默认级别就是Read committed)。
  • Read uncommitted(读未提交):脏读、不可重复读和幻读都可能发生。

分别对应Connection类中的四个常量:

  • TRANSACTION_SERIALIZABLE
  • TRANSACTION_REPEATABLE_READ
  • TRANSACTION_READ_COMMITTED
  • TRANSACTION_READ_UNCOMMITTED
隔离级别 脏读 不可重复读 幻读
Serializable
Repeatable read
Read committed
Read uncommitted
  • ✅:可能出现
  • ❎:不会出现

# 隔离级别与锁的关系

# 脏读

一个事务读取到另外一个事务未提交的数据。

比如,A向B转账,A已经执行了转账语句,但是A还没有提交事务,这时候B读取数据时发现自己账户余额已经变多了。如果B通知A已经收到钱后,A又执行回滚事务(rollback),那么B再查看账户就会发现余额没有变多。

# 不可重复读

一个事务读取到另外一个事务已经提交的数据,即一个事务可以看到其它事务所做的修改。

例如,A查询数据库,而B修改了数据库的数据,这就会导致A多次查询数据库的结果都不一样。这就发生了在一个事务内多次读到的数据是不一样的,就称为不可重复读。

# 幻读(虚读)

一个事务读取到了别的事务插入的数据,导致前后读取不一致。

例如,事务A对一个表中的所有数据都进行了修改,同时,事务B向这个表插入了一行新的数据,那么操作事务A的用户就发现有一行新的数据没有修改到,前后读取不一致,仿佛产生了幻觉,叫做幻读(虚读)。

# 总结

脏读是不可容忍的,不可重复读和幻读在一定情况下是可以的。