2023-08-11 21:44:40
事务的ACID四大原则
事务(Transaction)是访问和更新数据库的程序执行单元,事务中可能包含一个或多个SQL语句,这些语句要么都执行,要么都不执行。ACID是衡量事务的四个特性,下面将详细解释这四个特性:
1. 原子性(Atomicity)
原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做。在数据库中,如果事务中一个SQL语句执行失败,则已执行的语句也必须回滚,数据库退回到事务前的状态。然而,需要注意的是,MySQL的事务并不支持完全的原子性。在MySQL中,如果事务中的一条SQL无法执行,它会将这一条SQL报错,并继续执行接下来的SQL,且已执行的SQL也不回滚,除非我们主动使用逻辑判断要求报错时执行回滚,否则MySQL的事务本身是不会回滚的。
2. 持久性(Durability)
持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。简单理解,就是数据的持久化。即使系统崩溃或断电,已提交的事务对数据库的改变也不会丢失。这是因为数据库系统通常会将已提交的事务记录到持久化存储中,如硬盘。
3. 隔离性(Isolation)
隔离性研究的是不同事务之间的相互影响。隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。通常使用锁机制来保证事务的隔离性。
锁机制:MySQL数据库中,MyISAM存储引擎只支持表锁,InnoDB存储引擎同时支持表锁和行锁,出于性能考虑,绝大多数情况下使用的都是行锁。
脏读、不可重复读和幻读:若不保证事务的隔离性,则有可能会出现数据的脏读、不可重复读和幻读。
脏读:当前事务中可以读到其他事务未提交的数据(脏数据)。
不可重复读:在事务中先后两次读取同一个数据,两次读取的结果不一样。脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。
幻读:在事务中按照某个条件先后两次查询数据库,两次查询结果的条数不同。不可重复读与幻读的区别可以通俗地理解为:前者是数据变了,后者是数据的行数变了。
事务隔离级别:SQL标准中定义了四种隔离级别,并规定了每种隔离级别下上述问题是否存在。一般来说,隔离级别越低,系统开销越低,可支持的并发越高,但隔离性也越差。隔离级别与读问题的关系如下:
读未提交(Read Uncommitted):允许读取未提交的数据,可能导致脏读、不可重复读和幻读。
读已提交(Read Committed):只允许读取已提交的数据,可以避免脏读,但可能出现不可重复读和幻读。
可重复读(Repeatable Read):保证在同一个事务中多次读取同一数据的结果一致,可以避免脏读和不可重复读,但幻读仍有可能发生(不过InnoDB通过MVCC避免了幻读问题)。
可串行化(Serializable):强制事务串行执行,避免脏读、不可重复读和幻读,但并发性能最低。
在实际应用中,读未提交在并发时会导致很多问题,而性能相对于其他隔离级别提高却很有限,因此使用较少。可串行化强制事务串行,并发效率很低,只有当对数据一致性要求极高且可以接受没有并发时使用,因此使用也较少。因此在大多数数据库系统中,默认的隔离级别是读已提交(如Oracle)或可重复读(如InnoDB)。
4. 一致性(Consistency)
一致性是指事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态。数据库的完整性约束包括但不限于:实体完整性(如行的主键存在且唯一)、列完整性(如字段的类型、大小、长度要符合要求)、外键约束、用户自定义完整性(如转账前后,两个账户余额的和应该不变)。简单理解,就是事务执行前后,数据的改变都是合法,且各方数据都是一致的。
事务的目的就是为了数据一致性。为了实现事务的一致性,需要保证事务的原子性、持久性和隔离性,同时数据库本身需要提供保障,完善其完整性约束。此外,应用层面也需要进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,也无法保证状态的一致。
综上所述,ACID四大原则是衡量事务特性的重要标准,它们共同保证了事务的可靠性和数据的一致性。