什么是数据库事务?
数据库的事务是一种机制、一个操作序列,包含了一组数据库命令,其执行的结果必须使数据库从一种一致性状态到另一种一致性状态。
事务把所有的命令作为一个整体一起向系统提交或撤销操作请求,是一个不可分割的工作逻辑单元。
如果任意一个操作失败,那么整租操作即为失败,会回到操作前状态或者是上一个节点。
因此,事务是保持逻辑数据一致性和可恢复性的重要利器。而锁是实现事务的关键,可以保证事务的完整性和并发性。
有哪些事务状态?
事务在其整个生命周期中会经历不同的状态,这些状态也称为事务状态。
- 活跃状态:事务的第一个状态,任何正在执行的事务都处于此状态,所做的更改存储在主内存的缓冲区中。
- 部分提交状态:执行上述操作后,事务进入部分提交状态,所做的更改仍在主内存的缓冲区中。
- 失败状态:如果某个检查在活动状态下失败,在活动状态或部分提交状态发生一些错误,并且事务无法进一步执行,则事务进入失败状态。
- 中止状态:如果任何事务已达到失败状态,则恢复管理器将数据库回滚到开始执行的原始状态。
- 提交状态:如果所有操作成功执行,则来自部分提交状态的事务进入提交状态。无法从此状态回滚,它是一个新的一致状态。
事务的四大特性
事务具有4个特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),简称ACID,关系型数据库需要遵循ACID原则。
- 原子性:事务最小的执行单位,不可分割(原子)的。该特性确保动作要么全部执行,要么全部不执行,即事务不能部分提交。
- 一致性:当事务完成时,数据必须处于一致性状态,多个事务对同一个数据读取的结果是相同的。
- 隔离性:并发访问数据库时,一个用户的事务不被其他事物所干扰,各个事务不干涉内部的数据。修改数据的事务可以在另一个使用相同数据的事务开始之前/结束之后访问这些数据。
- 持久性:一个事务被提交之后,它对数据库中的数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
如何实现事务的ACID特性
事务的ACID特性是由关系数据库管理系统来实现的。
DBMS采用日志来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态。
DBMS采用锁机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新。
事务之间的相互影响
- 脏读(Dirty Read):一个事务读取了另一个事务未提交的数据。
- 不可重复读(Non-repeatable Read):就是一个事务范围内,两次相同的查询会返回两个不同的数据,这是因为在此间隔内其他事务对数据进行了修改。
- 幻读(Phantom Read):指当事务不是独立执行时发生的一种现象。如一个事务对所有数据进行修改的同时,另一个事务对数据插入了一行数据,第一个事务就会发现表中还有没修改的数据行,就像发生了幻觉一样。
- 丢失更新(Lost Update):两个事务同时读取同一条记录,事务a先修改记录,事务b也修改记录(事务b不知道a修改过),当b提交时,其修改结果覆盖了a的修改结果,导致事务a更新丢失。
什么是事务的隔离级别
为了尽可能地避免上述事务之间的相互影响,从而达到事务的四大特性,SQL标准定义了4种不同的事务隔离级别(TRANSACTION ISOLATION LEVEL),即并发事务对同一资源的读取深度层次,由低到高是:读取未提交、读取已提交、可重复读、可串行化:
- 读取未提交:最低的隔离级别,一个事务可以读到另一个事务未提交的结果,所有的并发事务问题都会发生。
- 读取已提交:只有在事务提交后,其更新结果才会被其他事务看见。Oracle默认采用该隔离级别。
- 可重复读:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交,除非数据是被本身事务自己所修改。MySQL默认采用可重复读隔离级别。
- 可串行化:事务串行化执行(所有事务依次逐个执行),隔离级别最高,完全服从ACID,牺牲了系统的并发性。
这4个级别与事务相互间影响问题对应如下:
隔离级别 | 脏读 | 不可重复读 | 幻读 | 丢失更新 |
---|---|---|---|---|
读取未提交 | 是 | 是 | 是 | 是 |
读取已提交 | 否 | 是 | 是 | 是 |
可重复读 | 否 | 否 | 是 | 否 |
可串行化 | 否 | 否 | 否 | 否 |