数据库原理 第五章 事务与并发控制
1.事务的基本概念
1.1为什么需要事务?什么是事务?
数据库事务(Database Transaction) 是指一组数据库操作的集合,这些操作要么全部执行成功,要么全部不执行。事务是为了确保数据库中的数据一致性和完整性而设计的。
1.2数据库事务的四大特性(ACID)
数据库事务有四个关键特性,通常简称为 ACID:
-
原子性(Atomicity):事务中的操作要么全部成功,要么全部失败。如果事务中的某个操作失败,事务的所有操作都会回滚,数据库恢复到事务开始前的状态。
-
一致性(Consistency):事务执行前后,数据库的状态应保持一致。如果事务执行成功,数据应该从一个一致性状态转变到另一个一致性状态。
-
隔离性(Isolation):事务的执行不受其他事务干扰。即使多个事务并发执行,每个事务也会感觉自己是独占数据库的,其他事务的操作在它提交之前是不可见的。事务之间的隔离级别可以调整,通常有四种:读未提交、读已提交、可重复读和串行化。
-
持久性(Durability):一旦事务提交,对数据库的修改是永久性的,即使系统崩溃也不会丢失。
1.3事务涉及的基本概念
在数据库管理系统中,transaction
(事务)、rollback
(回滚)、commit
(提交)和savepoint
(保存点)是管理和控制数据库操作的核心概念。它们帮助确保数据的一致性、完整性和可靠性。
1.3.1 Transaction(事务)
事务是数据库中一组操作的集合,这些操作被视为一个单独的工作单元。事务的基本特点是要么完全执行(提交),要么完全不执行(回滚),从而保证数据的一致性。
事务的生命周期通常包括以下步骤:
- 启动事务(例如执行某些数据库操作)
- 进行一系列操作(插入、更新、删除等)
- 提交事务(如果所有操作都成功)
- 或者回滚事务(如果某个操作失败)
1.3.2. Rollback(回滚)
回滚操作用于撤销事务中的所有更改。回滚将数据库恢复到事务开始之前的状态。它通常在以下情况下触发:
- 在事务执行过程中发生了错误或异常。
- 用户决定撤销事务中的操作(例如,出现了数据验证失败的情况)。
回滚操作确保了事务中的操作不会对数据库造成不一致的影响。
例子: 假设你正在做一个银行转账操作。如果从账户A扣款成功,但向账户B存款失败,那么执行回滚操作会撤销扣款操作,保证两个操作一起成功或者一起失败。
1.33. Commit(提交)
提交操作用于确认并保存事务中的所有更改。提交后,所有对数据库的修改将被永久保存,无法回滚。提交意味着事务的操作已经成功执行,数据库的状态已经更新。
一旦事务执行完成,调用 commit
将使事务中的所有修改生效,其他用户可以看到这些修改。
例子: 如果银行转账操作中的所有步骤都顺利完成(例如,扣款和存款都成功),你会调用 commit
来保存这两个操作的结果,确保这些操作对数据库的影响是永久的。
1.3.4. Savepoint(保存点)
保存点是事务中的一个标记点,它允许你在事务执行过程中指定一个“中间状态”。通过设置保存点,你可以在事务的某个位置创建一个恢复点。如果后续操作失败,你可以回滚到这个保存点,而不是回滚整个事务。
保存点提供了一种精细化的回滚机制,它比 rollback
更具灵活性,因为回滚到保存点不会影响保存点之前的操作。
例子: 在一个复杂的事务中,你可能会执行多个步骤。例如,转账操作包含多个子步骤:检查账户余额、扣款、存款等。你可以在“检查账户余额”这一步设置一个保存点。如果在“存款”过程中出错,你可以仅回滚到保存点,从而撤销存款操作,而不会影响其他步骤(如账户余额检查或扣款)。
1.3.5关系总结
概念 | 描述 |
---|---|
Transaction | 一组数据库操作,要么全部成功(commit ),要么全部失败(rollback )。 |
Rollback | 回滚操作,撤销事务中的所有操作,恢复到事务开始前的状态。 |
Commit | 提交操作,保存事务中的所有更改,确保修改永久生效。 |
Savepoint | 事务中的中间点,允许回滚到事务中的某个指定位置,而不是回滚整个事务。 |
1.4MySQL 事务管理的完整示例
假设我们需要进行一个简单的转账操作,将 100 元从账户 A 转账到账户 B,以下是完整的事务操作,包括保存点和回滚的用法。
示例:转账操作
-- 开始事务
START TRANSACTION;
-- 步骤1:检查账户A余额
SELECT balance FROM accounts WHERE account_id = 'A';
-- 步骤2:设置保存点
SAVEPOINT check_balance;
-- 步骤3:扣除账户A的余额
UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A';
-- 步骤4:存款到账户B
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B';
-- 步骤5:提交事务
COMMIT;
-- 如果在过程中有错误发生,可以回滚到保存点,撤销后续操作
-- 如果账户A余额不足时,回滚到保存点撤销存款操作
ROLLBACK TO SAVEPOINT check_balance;
-- 事务失败时,完全回滚
-- ROLLBACK;
事务管理的说明
-
开启事务:通过
START TRANSACTION
开始事务,接下来的所有 SQL 操作都在这个事务中执行,直到你执行COMMIT
或ROLLBACK
。 -
保存点:使用
SAVEPOINT
设置保存点,可以在事务中设置多个保存点,回滚到某个保存点时,只会撤销从该保存点之后的操作,而不会影响保存点之前的操作。 -
回滚:如果事务中的某个操作失败,可以通过
ROLLBACK
或ROLLBACK TO SAVEPOINT
进行回滚,恢复到事务开始前的状态(或者到某个保存点的状态)。 -
提交事务:如果事务中的所有操作都成功,可以使用
COMMIT
提交事务,所有更改将永久生效。
2.故障
2.1故障的种类
在计算机科学中,特别是在数据库管理系统(DBMS)中,故障通常是指系统在操作过程中出现了异常或错误,导致无法按照预期进行工作。以下是您提到的几种故障的具体解释:
2.1.1. 数据库事务故障 (Transaction Failure)
事务故障是指在数据库操作过程中,事务未能成功完成。一个事务(Transaction)通常是指一系列数据库操作,要么完全执行,要么完全不执行,这被称为“原子性”(Atomicity)。事务故障可能是由于程序错误、逻辑冲突、约束违规等原因导致的。
-
原因:
- 应用程序错误
- 数据库约束不满足(如主键冲突、唯一性约束等)
- 死锁(多个事务互相等待资源)
-
影响: 事务未能成功提交,数据库的数据完整性可能受到影响。
-
解决方法:
- 使用事务回滚(Rollback)来撤销已经执行的操作,确保数据库恢复到一致状态。
2.1.2. 系统故障 (System Failure)
系统故障是指计算机硬件或软件出现严重问题,导致整个系统(包括数据库管理系统)无法正常运行。这种故障可能影响数据库的可用性或完整性。
-
原因:
- 操作系统崩溃
- 数据库软件的崩溃
- 内存不足、CPU超负荷等硬件问题
-
影响: 数据库可能无法启动,部分或所有数据可能丢失,或者数据库无法响应用户请求。
-
解决方法:
- 定期备份数据库,确保数据可恢复。
- 使用高可用性系统设计(如主从复制、故障转移机制)来减少系统故障的影响。
2.1.3. 介质故障 (Media Failure)
介质故障指的是存储介质(如硬盘、磁带等)的损坏或故障。数据库数据存储在硬盘或其他存储设备上,介质故障可能导致数据丢失、损坏或无法访问。
-
原因:
- 存储设备损坏(如硬盘损坏、电池故障等)
- 磁盘文件系统损坏
- 外部环境(如电力故障、自然灾害等)
-
影响: 数据可能变得不可读取或丢失,甚至系统无法启动。
-
解决方法:
- 使用 RAID 技术或冗余存储系统,确保数据在介质损坏时可以恢复。
- 定期进行数据备份和恢复演练,确保可以从备份中恢复丢失的数据。
2.1.4. 计算机病毒 (Computer Virus)
计算机病毒是指一种恶意软件,它能够自我复制并传播,通常会对计算机系统、文件或程序造成破坏。病毒可以感染数据库系统,并可能导致数据丢失、泄露、修改或系统瘫痪。
-
原因:
- 被感染的文件、程序或操作系统
- 下载或安装了含有病毒的外部程序或文件
- 网络传播的病毒
-
影响:
- 数据篡改、丢失或泄漏
- 系统崩溃、性能下降
- 未授权的远程访问和控制
-
解决方法:
- 使用防病毒软件定期扫描和清除病毒。
- 实施安全的防护策略,如防火墙、访问控制、定期软件更新等,防止病毒入侵。
2.1.5总结
- 事务故障与数据库的操作逻辑和数据一致性相关。
- 系统故障涉及到整个系统的崩溃或不可用。
- 介质故障是指存储硬件的损坏,导致数据丢失或无法访问。
- 计算机病毒则是指恶意软件导致的损害,可能影响数据的完整性和系统的安全。
这些故障都是在设计和维护数据库系统时必须考虑的重要因素,因此需要采取相应的预防措施,如备份、容错、加密、安全策略等。
3.恢复技术
恢复机制涉及的关键问题
- 如何建立冗余数据
- 数据转储(backup)
- 登录日志文件(logging)
- 如何利用这些冗余数据实施数据库恢复
数据库恢复机制的核心目的是在发生故障(如系统崩溃、硬件损坏、软件错误等)时,能够尽可能地恢复数据的完整性和一致性,保证数据库的正常运行。建立有效的冗余数据、日志文件机制以及合理的数据转储策略是数据库恢复的关键。
3.1.冗余数据的建立
冗余数据是指将数据库中的数据以多种形式存储在不同的物理介质上,从而在发生故障时能够恢复数据。建立冗余数据可以有效防止数据丢失,并加速恢复过程。以下是常见的冗余数据策略:
(1) 数据复制(Replication)
- 主从复制(Master-Slave Replication):将数据库的所有变更同步到一个或多个从数据库节点。如果主数据库发生故障,可以切换到从数据库进行继续操作。
- 多主复制(Multi-Master Replication):多个数据库节点都可以进行写操作,所有节点的数据始终保持同步。此策略适用于高可用性和高容错需求的场景。
(2) RAID(Redundant Array of Independent Disks)
- RAID 1(镜像):将数据复制到两个硬盘中,即使一个硬盘发生故障,数据仍然可以从另一个硬盘恢复。
- RAID 5(带奇偶校验):利用数据和奇偶校验信息分布在多个磁盘上,当一个磁盘发生故障时,可以通过剩余的磁盘和奇偶校验信息恢复数据。
- RAID 10(镜像+条带):结合RAID 1和RAID 0的特点,提供更高的读写性能和数据冗余。
(3) 数据库快照(Snapshots)
- 快照是对数据库当前状态的完整备份,通常在数据库更新时创建。快照可以存储在不同的存储位置,一旦发生故障,能迅速回滚到快照时的数据库状态。
3.2. 数据转储(Backup)
数据转储是指将数据库的当前状态或某一时刻的数据复制到另一个安全存储位置(如磁带、云存储、外部硬盘等),以防止数据丢失。常见的备份策略包括:
(1) 全量备份(Full Backup)
- 对整个数据库进行备份,包括所有表、索引、视图等。全量备份确保了备份数据的完整性,但通常需要较长时间和较多存储空间。
(2) 增量备份(Incremental Backup)
- 只备份自上次备份以来发生变化的数据。增量备份比全量备份更节省存储空间,并且备份速度较快,但恢复时需要依赖全量备份和所有增量备份的顺序。
(3) 差异备份(Differential Backup)
- 备份自上次全量备份以来发生变化的数据。恢复时,通常只需要全量备份和最新的差异备份。
(4) 日志备份(Transaction Log Backup)
- 对数据库的事务日志进行备份,记录了自上次日志备份以来的所有事务。日志备份可以帮助恢复数据库到某个时间点,确保数据的一致性。
3.3. 日志文件(Logging)
日志文件记录了数据库中所有的事务活动,确保数据的一致性和完整性。日志文件对于数据库恢复至关重要,尤其是在发生系统崩溃时,可以利用日志来回滚(Undo)或重做(Redo)事务。日志文件通常分为以下两类:
(1) 事务日志(Transaction Log)
- 每个事务都会在日志文件中记录开始、提交、回滚等信息。事务日志的作用是确保数据库的持久性和一致性。
- 在发生崩溃时,日志可以帮助我们恢复到事务提交之前或之后的某个一致状态。
- 通过 WAL(Write-Ahead Logging),事务日志在数据库操作之前被写入磁盘,确保即使发生崩溃,所有已经提交的事务可以被重做。
(2) 重做日志和回滚日志(Redo/Undo Logs)
- 重做日志(Redo Log):记录已经提交的事务的修改操作,发生崩溃后可以重做这些操作,确保提交的事务数据不丢失。
- 回滚日志(Undo Log):记录未提交的事务的修改操作,用于恢复事务失败时将已修改的数据回滚到原来的状态。
3.4. 利用冗余数据、日志和备份实施恢复
利用冗余数据、日志文件和数据转储,可以实现数据库的故障恢复。主要的恢复方法包括:
(1) 完全恢复(Full Recovery)
- 适用于数据库发生故障或崩溃,利用全量备份、增量备份和日志备份来恢复数据库到故障发生之前的最新状态。
- 恢复步骤:
- 恢复最后一个全量备份。
- 恢复所有相关的增量备份或差异备份。
- 通过事务日志进行重做,恢复所有已提交的事务。
(2) 时间点恢复(Point-in-Time Recovery)
- 当需要恢复到特定时间点的数据库状态时,使用时间点恢复。利用备份和日志文件可以将数据库恢复到故障发生前的某个时间点。
- 恢复步骤:
- 恢复最后一个全量备份。
- 恢复相关的增量或差异备份。
- 使用事务日志回滚至指定的时间点。
(3) 快速恢复(Fast Recovery)
- 使用数据库的冗余数据,如复制和快照,快速恢复服务。通常用于对系统可用性要求较高的场景,通过快速切换到备用系统或恢复快照,减少数据库停机时间。
(4) 灾难恢复(Disaster Recovery)
- 当发生严重故障(如硬件损坏、自然灾害等)时,使用冗余数据、远程备份和分布式复制机制实现灾难恢复。
- 通过主从复制或跨数据中心的备份,能够将故障恢复时间降到最低。
总结
数据库的恢复机制依赖于多种技术手段,如冗余数据存储、日志记录和数据备份。通过合理设计这些机制,可以确保在系统故障、硬件损坏、数据丢失等情况下,能够快速、可靠地恢复数据库到一致的状态。实现高可用性和灾难恢复是保障数据库系统长期稳定运行的关键。
4.并发控制
在数据库管理系统中,事务并发执行是指多个事务同时执行的情况。由于多个事务可能在同一时间访问和修改相同的数据,这种并发操作会导致一些并发问题。为了解决这些问题,数据库系统采用了各种并发控制技术,如锁机制和乐观控制(MVCC)等。
4.1. 并发可能带来的问题
并发执行事务时,可能出现以下三种常见的问题:
(1) 丢失修改(Lost Update)
- 定义:丢失修改是指两个或多个事务并发执行时,其中一个事务的修改被另一个事务的修改所覆盖,导致某些数据的更新丢失。
- 示例:
- 事务 T1 读取数据
X = 100
,然后将其更新为X = 150
。 - 事务 T2 也读取数据
X = 100
,然后将其更新为X = 120
。 - 结果是
X = 120
,而 T1 的更新被丢失。
- 事务 T1 读取数据
(2) 不可重复读(Non-repeatable Read)
- 定义:不可重复读是指在一个事务中,某个数据在多次读取时,读取结果发生了变化。这通常发生在一个事务读取数据后,另一个事务对该数据进行了修改或删除。
- 示例:
- 事务 T1 读取数据
X = 100
。 - 事务 T2 更新了
X
,将其改为X = 150
。 - 当 T1 再次读取
X
时,得到X = 150
,这与第一次读取的结果不同。
- 事务 T1 读取数据
(3) 读“脏”数据(Dirty Read)
- 定义:读“脏”数据是指一个事务读取了另一个事务尚未提交的数据。如果该事务随后被回滚,读取到的数据就会成为无效或“脏”数据。
- 示例:
- 事务 T1 更新了数据
X
,将其从X = 100
改为X = 150
,但还没有提交。 - 事务 T2 读取了
X = 150
,即使 T1 没有提交,如果 T1 随后回滚,T2 读取到的X = 150
就是脏数据。
- 事务 T1 更新了数据
4.2. 并发控制的主要技术
为了解决并发带来的问题,数据库系统通常采用以下两种并发控制技术:封锁机制(Locking) 和 乐观控制法 / 多版本并发控制(MVCC)。
(1) 封锁(Locking)
封锁机制是通过在事务访问数据时加锁,确保同一时刻只有一个事务可以访问特定的数据。常见的锁有以下几种:
- 共享锁(Shared Lock,S-Lock):事务可以读取数据,但不能修改数据。如果某个事务对数据加了共享锁,其他事务可以对该数据加共享锁,但不能修改它。
- 排它锁(Exclusive Lock,X-Lock):事务不仅可以读取数据,还可以修改数据。如果某个事务对数据加了排它锁,其他事务既不能读取也不能修改该数据。
封锁的优势:
- 通过严格控制数据的访问,避免了并发问题,如丢失修改、不可重复读和读脏数据。
封锁的缺点:
- 死锁(Deadlock):如果两个或更多事务互相持有对方需要的锁,导致事务无法继续执行,形成死锁。
- 性能损失:长时间持锁会影响并发性,导致数据库性能下降。
常见的封锁协议有:
- 两段锁协议(Two-Phase Locking,2PL):事务在执行过程中,先加锁再释放锁,锁的释放只能发生在事务的最后阶段(提交或回滚)。这种协议可以避免丢失修改、不可重复读和脏读。
(2) 乐观控制法 / 多版本并发控制(MVCC)
多版本并发控制(MVCC)是一种基于乐观锁的并发控制机制,它允许事务在无需加锁的情况下,创建数据的多个版本。每个事务可以看到不同版本的数据,从而避免了因加锁带来的并发性问题。
4.3MVCC 的工作原理:
- 数据版本管理:数据库系统维护每个数据项的多个版本,每个事务在开始时获得一个时间戳或事务ID,用于标识它所看到的数据版本。
- 事务提交时的版本检查:在事务提交时,系统检查该事务操作的数据是否已被其他事务修改。如果有冲突(例如,其他事务已经提交了更新),则回滚当前事务。
- 并发读取:因为每个事务看到的是它开始时的数据库版本,因此事务可以并发读取数据,而不需要等待其他事务完成。
MVCC 的优势:
- 无锁并发:MVCC 允许多个事务并行读取不同版本的数据,避免了锁竞争,因此提高了并发性能。
- 避免了死锁:由于不需要加锁,MVCC 避免了死锁问题。
MVCC 的缺点:
- 空间开销:每个数据项维护多个版本,需要额外的存储空间。
- 版本管理复杂性:维护多个版本的数据需要额外的机制来确保版本的有效性和清理过时版本。
MVCC 的实现机制
MVCC 通过为每个数据项存储版本号(通常是事务ID)来实现多版本数据存储。每当事务修改数据时,系统会生成一个新的数据版本并赋予它一个新的时间戳或事务ID。读取操作则会根据事务的开始时间戳选择合适的版本。
总结:
- 丢失修改、不可重复读和脏读是并发执行事务时可能出现的并发问题。
- 为了解决这些问题,数据库系统通常采用封锁机制和MVCC(多版本并发控制)两种并发控制技术。
- 封锁机制通过加锁来防止并发事务之间的冲突,但可能导致性能问题,如死锁。
- MVCC则通过多版本数据存储和乐观控制来提高并发性,避免锁的竞争,但需要额外的空间和版本管理。
根据应用场景的不同,数据库系统可能采用不同的并发控制技术来平衡性能和数据一致性需求。