面试的时候,总会被问到事务。很多时候知道是怎么回事,但是回答的时候又是那么吞吞吐吐的,反而表达不清楚。仔细想想,表达不清楚那是因为自己还不熟悉。所以将先前的一些资料重新整理了一下。
什么是数据库事务
数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。
- 原子性:表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的原子操作执行成功,整个事务才提交;事务中任何一个数据库操作失败,已经执行的任何操作都必须撤销,让数据库返回到初始状态。
- 一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。如从A账户转钱到B账户,不管成不成功,A账户与B账户的总额是不变的。
- 隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对对方产生干扰。也就是说,一个事务直到它被成功提交之后,它的结果对于任何其他的事务才是可见的。
- 持久性:一个已提交事务的任何结果都必须是永久性的,即“在任何系统奔溃的情况下都能够保存下来”。
数据并发的问题
在多个客户端对数据库进行并发操作的时候,会出现一些并发问题。这些问题可以归纳为5类:3类数据读问题(脏读、不可重复读和幻读)和2类数据更新问题(第一类丢失更新和第二类丢失更新)。
脏读(dirty read)
A事务读取B事务尚未提交的更改数据,并在这个数据的基础上操作。
不可重复读(unrepeatable read)
A事务读取了B事务已经提交的更改数据。
幻读(phantom read)
A事务读取B事务提交的新增数据。这个时候A事务出现幻读问题。幻读一般发生在计算统计的事务当中。
幻读和不可重复读的区别:幻读是指读到了其他已经提交事务的新增数据;不可重复读是指读到了已经提交事务的更改数据(更改或删除)。防止读取到更改数据,只需要对操作的数据添加行级锁,阻止操作中的数据发生变化;防止读取到新增的数据,往往需要添加表级锁——将整个表锁定,防止新增数据。
第一类丢失更新
A事务撤销时,把已经提交的B事务的更新数据覆盖了。
第二类丢失更新
A事务覆盖B事务已经提交的数据,造成B事务所做的操作丢失。
数据库锁机制
表锁定和行锁定
按照锁定的对象的不同可以分为表锁定和行锁定。表锁定是对整个表进行锁定。行锁定对表中特定的行进行锁定。
共享锁定和独占锁定
从并发事务锁定的关系上来说,可以分为共享锁定和独占锁定。共享锁定会防止独占锁定,但允许其他的共享锁定。独占锁定既防止其他的独占锁定也防止其他的共享锁定。
事务隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 | 第一类丢失更新 | 第二类丢失更新 |
---|---|---|---|---|---|
READ UNCOMMITTED(读未提交) | 允许 | 允许 | 允许 | 不允许 | 允许 |
READ COMMITTED(读已提交) | 不允许 | 允许 | 允许 | 不允许 | 允许 |
REPEATABLE READ(可重复读) | 不允许 | 不允许 | 允许 | 不允许 | 不允许 |
SERIALIZABLE(串行化) | 不允许 | 不允许 | 不允许 | 不允许 | 不允许 |
- SERIALIZABLE(串行化):可避免脏读、不可重复读、幻读的发生。
- REPEATABLE READ(可重复读):可避免脏读、不可重复读的发生。
- READ COMMITTED(读已提交):可避免脏读的发生。
- READ UNCOMMITTED((读未提交):最低级别,任何情况都无法保证。
事务的隔离级别和数据库的并发是向对立的。READ UNCOMMITTED的隔离级别低,但拥有最高的并发性和吞吐量。SERIALIZABLE的隔离级别高,但并发性低。
默认的隔离级别是REPEATABLE READ(可重复读)