ACID模型是什么
ACID模型是数据库管理系统中保证事务处理安全性的一组特性。ACID是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)四个英文单词的首字母缩写。这些特性确保数据库事务是安全可靠的,即便在出现故障或异常情况时也能保持数据的完整性和准确性。
原子性(Atomicity)
原子性是指事务(Transaction)中的所有操作要么全部完成,要么全部不执行,事务在执行过程中不应该留下中间状态。如果事务成功完成,则其修改将永久保存到数据库中;如果事务在执行过程中失败,则系统将撤销其所有操作,回到事务开始前的状态。
它确保数据的一致性和整体性,即便在面对系统错误、硬件故障或其他异常情况时。例如,考虑一个银行应用,其中一项事务是从一个账户转账到另一个账户。这个事务包括两个步骤:从一个账户扣款和向另一个账户存款。原子性确保这两个操作要么都完成,要么都不完成,从而避免只执行了一个操作而导致的账户不平衡。
在MySQL中,原子性主要通过事务日志来实现。当一个事务开始时,所有的更改都会先被写入到这个日志中。只有在事务成功完成后,这些更改才会被提交到数据库中。如果事务失败或系统崩溃,MySQL会利用这些日志来回滚事务,撤销所有未完成的更改。
事务日志是一种持久化存储机制,用于在执行事务的过程中记录事务的每个操作。这包括数据的修改、添加或删除等信息。如果系统发生故障,事务日志将被用来重做或撤销未完成的事务。
- 提交(Commit):当事务中的所有操作正常完成后,将通过一个提交操作永久地将这些变更写入数据库。
- 回滚(Rollback):如果在执行事务的过程中发生错误或其他问题,事务将被回滚,即撤销所有已执行的操作,返回到事务开始之前的状态。
一致性(Consistency)
一致性确保事务从一个一致的状态转变到另一个一致的状态。在事务开始和完成时,数据库的完整性约束都必须保持满足。这意味着数据库中的所有数据规则都应当被遵守,比如唯一性、外键约束等,确保数据库状态的合法性。
一致性的实施是为了避免数据冗余和维护数据完整性。考虑以下场景:
- 数据完整性:在银行系统中转账事务,不仅需要确保总金额保持不变,还需要确保不会因为软件错误、硬件故障或其他原因导致数据损坏。
- 业务规则的遵守:企业数据库通常需要执行复杂的业务规则,如库存不能低于某个阈值。一致性确保这些业务逻辑在数据修改后仍然成立。
数据库管理系统通过强制执行各种数据约束来保持一致性,例如:
- 主键约束:确保每个表中的记录具有唯一的标识。
- 外键约束:确保表之间的引用完整性。
- 检查约束(CHECK约束):确保特定的列满足预定的条件。
数据库事务通过使用事务控制语句来维护一致性,例如COMMIT
和ROLLBACK
:
- 提交(COMMIT):如果所有的操作都符合约束和业务规则,事务将被提交,所有数据修改将永久保存。
- 回滚(ROLLBACK):如果事务中的操作违反了约束或未能通过某些业务规则的验证,那么进行的所有修改将被撤销。
隔离性(Isolation)
隔离性是指当多个用户并发访问数据库时,数据库系统能够为每个用户的事务提供一个独立的运行环境,好像用户是在独自使用数据库一样。这防止了事务之间的不当交互,如更新丢失、脏读、不可重复读和幻读等问题。
MySQL提供了多种隔离级别来实现不同程度的事务隔离,包括READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。每种隔离级别都以不同的方式处理并发事务中的数据可见性和干扰,允许数据库管理员根据具体的应用需求来选择合适的隔离级别。
- READ UNCOMMITTED(未提交读RU):一个事务还没提交时,它做的变更就能被别的事务看到。因此,它可能导致脏读,即一个事务读取了另一个事务还未提交的数据。如果那个事务回滚,读取的数据就会变得无效。
- READ COMMITTED(已提交读RC):一个事务只能看到其他事务已经提交的修改。这可以避免脏读。然而,它仍然允许不可重复读的发生,因为在同一个事务中,一个记录的两次读取之间,其他事务可以修改或提交数据,从而导致不一致的查询结果。
- REPEATABLE READ(可重复读RR):保证在同一个事务中多次读取同一数据的结果是一致的,即该事务不会看到其他事务提交的对这些数据的修改。这个级别防止了脏读和不可重复读,但通常不能防止幻读,即事务在执行过程中其他事务插入符合查询条件的新记录。 InnoDB默认级别 。
- SERIALIZABLE(串行化):最高的隔离级别,它完全隔离事务,使得事务只能一个接一个地执行,而不是并发执行。这个级别可以防止脏读、不可重复读和幻读。实际上,它通过对涉及的数据集加锁(范围锁或其他机制),确保了事务之间完全的隔离。
在没有良好隔离性的数据库系统中,可能会发生多种并发问题,如:
- 脏读(Dirty Read):一个事务可能读取到另一个事务尚未提交的修改。
- 不可重复读(Non-repeatable Read):一个事务对同一数据的多次读取中,可能因其他事务已提交的更新而得到不同的结果。
- 幻读(Phantom Read):一个事务重新执行相同的查询,可能会发现已经提交的事务添加了满足查询条件的新记录。
- 丢失修改(Lost Update):两个事务同时修改同一数据,最终只有一个事务的修改得以保存。
持久性(Durability)
持久性意味着一旦事务被提交,它对数据库的更改就是永久性的,即使系统发生故障,这些更改也不会丢失。这通常通过将事务日志记录到非易失性存储器中实现。
持久性的核心作用是确保数据的可靠性和安全性。在任何需要长期保留关键数据的系统中,持久性都是至关重要的。例如,在银行系统中,交易记录的持久保存对于防止数据丢失和保证账户安全至关重要。
为了保证数据的持久性,数据库管理系统采用了多种技术和策略,其中包括:
写前日志(Write-Ahead Logging, WAL)
写前日志是一种常用的技术,用于保证事务的持久性。在这种机制下,任何数据的更改在实际写入数据库之前,首先被记录到日志文件中。这样,即使在数据写入过程中系统崩溃,数据库也可以在重启后使用日志文件恢复到最后一次成功的事务状态。
检查点(Checkpoints)
检查点是定期创建的数据库快照,记录了那一刻数据库的完整状态。通过创建检查点,数据库可以减少在系统崩溃后数据恢复所需的时间,因为它只需从最近的检查点开始重播日志文件,而不是从头开始。
复制和冗余
为了增强数据的持久性和提高系统的容错能力,许多数据库系统采用数据复制和存储冗余技术。通过在多个地点或设备上保存数据副本,即使主存储设备发生故障,也可以从副本中恢复数据。
事务的持久性确认
在某些数据库系统中,事务的持久性只有在相关的数据被物理写入到磁盘上后才会被确认。这通常涉及多个底层写操作,包括更新磁盘上的数据块和刷新磁盘缓存。
MySQL通过使用重做日志(redo log)来实现持久性。当事务被提交时,所有相关的更改都会被写入到这些日志中。即使数据库发生崩溃,重做日志也可以在系统恢复后被用来重建更改,确保事务的持久性。
参考链接
- ACID特性简介:https://en.wikipedia.org/wiki/ACID
- 数据库事务和ACID特性:https://www.ibm.com/docs/en/db2/11.5?topic=concepts-acid-properties