数据库事务特性初探
在使用数据库进行业务开发时,常常提到“事务”这一概念。这里的事务指的是对数据库的一组读写操作,并且这一系列操作需要具有 ACID 特性。
事务特性
ACID 由 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)四种特性组成。
Atomicity(原子性):构成事务的一组读写操作要么全部成功,要么全部失败。在成功提交时,数据修改落到数据库中,事务中的操作全部成功。当出现失败时,事务回滚将所有数据恢复到执行前的状态,所有操作全部失败。
Consistency(一致性):在数据库执行后,无论成功还是失败,数据库的完整性不会被破坏。数据库中的数据持续满足数据定义给出的要求。
Isolation(隔离性):在多个事务并发执行时,他们之间的干扰要满足一定的要求。这些不同的要求构成了不同的隔离级别。隔离级别包括:读未提交、读已提交、可重复读、可串行化。
Durability(持久性):在事务成功提交后,即使数据库管理系统发生故障,在恢复运行后,事务中提交的修改也不会丢失。
隔离级别
在数据库管理系统中,隔离性的要求与并发性能之间实质上是冲突的。为了保证更高的隔离性要求,就会降低数据库管理系统的并发性能。为了获得更高的并发性能,就需要容忍事务间隔离性的降低。因此,需要对不同隔离性下的并发性能、需要容忍的问题有清楚的认识才能规避问题,保证应用正确性。
下面是一些隔离性相关问题在不同隔离级别下可能性表:
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
读未提交 | ✅ | ✅ | ✅ |
读已提交 | ❌ | ✅ | ✅ |
可重复读 | ❌ | ❌ | ✅ |
可串行化 | ❌ | ❌ | ❌ |
其中,展示了脏读、不可重复读、幻读三种隔离性相关的问题。这些问题随着隔离性的提高而消除。为了消除这些问题,数据库管理系统也需要付出更高的并发性能代价。
脏读:读取到数据库中未正式出现的数据状态。在读未提交的隔离级别下,可能读取到正在执行的并发事务的中间状态。由于并发事务的回滚,这些中间状态可能并不会最终保存到数据库中从而形成脏读。而在读已提交的隔离级别下,由于未提交的数据对并发事务不可见,这种问题不会出现。
不可重复读:在一个事务中,事务本身并未修改的情况下多次读取同一数据得到不同的状态。在读已提交的隔离级别下,在事务执行过程中由于并发事务的提交,已读取的数据发生变化,就产生了不可重复读的问题。可重复读的隔离级别下则明确地排除了这一问题,在数据读取完成后再次读取一定得到同样的结果。
幻读:在事务中进行查询时,得到的结果行数发生变化。这是由于在并发事务中进行了数据的插入或删除而产生的。它与不可重复读的不同之处在于,不可重复读关注具体行数据的内容变化,而幻读关注表数据的行数变化。因此它们间的级别不一样,规避时需要付出的并发性能代价也不一样。要彻底避免幻读的问题,需要在表级别进行限制,因此在可串行化这一高度降低并发性能的隔离级别上才能解决。
在 Oracle, PostgreSQL, SQL Server 数据库管理系统上,默认隔离级别为读已提交。而 MySQL InnoDB 引擎默认隔离级别为可重复读。