ACID 是事务处理系统的四个关键特性,用于确保数据库的可靠性。这四个特性分别是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。下面详细解释每一个特性,并结合示例代码来说明它们在 MySQL 中的实现。
1. 原子性(Atomicity)
原子性确保事务中的所有操作要么全部成功,要么全部失败。事务的所有操作作为一个整体,一起提交或回滚。
示例代码
假设我们有一个 accounts
表,我们要从一个账户转账到另一个账户:
-- 创建 accounts 表
CREATE TABLE accounts (
account_id INT AUTO_INCREMENT PRIMARY KEY,
account_name VARCHAR(100) NOT NULL,
balance DECIMAL(10, 2) NOT NULL
);
-- 插入初始数据
INSERT INTO accounts (account_name, balance) VALUES ('Alice', 1000.00);
INSERT INTO accounts (account_name, balance) VALUES ('Bob', 1000.00);
-- 开始事务
START TRANSACTION;
-- 从 Alice 的账户减去 100 元
UPDATE accounts SET balance = balance - 100 WHERE account_name = 'Alice';
-- 向 Bob 的账户增加 100 元
UPDATE accounts SET balance = balance + 100 WHERE account_name = 'Bob';
-- 如果两个操作都成功,则提交事务
COMMIT;
-- 如果有任何错误,则回滚事务
-- ROLLBACK;
在这个示例中,如果任何一个 UPDATE
操作失败,整个事务将会回滚,保证原子性。
2. 一致性(Consistency)
一致性确保事务执行前后,数据库从一个一致状态转换到另一个一致状态。所有约束(如外键约束、唯一性约束等)在事务执行前后都必须满足。
示例代码
在上面的示例中,如果 balance
列有一个检查约束确保余额不能为负数:
-- 添加约束,确保余额不能为负数
ALTER TABLE accounts ADD CONSTRAINT chk_balance CHECK (balance >= 0);
-- 开始事务
START TRANSACTION;
-- 从 Alice 的账户减去 1100 元(超过余额)
UPDATE accounts SET balance = balance - 1100 WHERE account_name = 'Alice';
-- 向 Bob 的账户增加 1100 元
UPDATE accounts SET balance = balance + 1100 WHERE account_name = 'Bob';
-- 提交事务(由于约束,事务会失败并回滚)
COMMIT;
-- 如果有任何错误,则回滚事务
-- ROLLBACK;
在这个示例中,由于违反了 CHECK
约束,事务将回滚,确保一致性。
3. 隔离性(Isolation)
隔离性确保并发事务之间互不干扰,一个事务的中间状态对其他事务不可见。MySQL 提供四种隔离级别:READ UNCOMMITTED
、READ COMMITTED
、REPEATABLE READ
(默认)和 SERIALIZABLE
。
示例代码
假设我们有两个并发事务:
-- 设置会话隔离级别为 REPEATABLE READ
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 事务 A
START TRANSACTION;
SELECT balance FROM accounts WHERE account_name = 'Alice';
-- 等待事务 B 完成后继续
-- ...
-- 提交事务 A
COMMIT;
-- 事务 B
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_name = 'Alice';
COMMIT;
在这个示例中,事务 A 在读取 Alice
的余额后,事务 B 对 Alice
的余额进行了更新。由于隔离级别为 REPEATABLE READ
,事务 A 在整个事务期间读取到的 Alice
余额是一致的,不会受到事务 B 的影响。
4. 持久性(Durability)
持久性确保一旦事务提交,所有修改将永久保存,即使系统崩溃也不会丢失。
示例代码
-- 开始事务
START TRANSACTION;
-- 更新操作
UPDATE accounts SET balance = balance - 100 WHERE account_name = 'Alice';
UPDATE accounts SET balance = balance + 100 WHERE account_name = 'Bob';
-- 提交事务
COMMIT;
在这个示例中,一旦事务提交,Alice 和 Bob 的账户余额修改将持久保存,即使系统崩溃也不会丢失。
事务的完整示例
以下是一个完整的事务示例,展示了 ACID 特性的实现:
-- 创建数据库
CREATE DATABASE bank;
-- 选择数据库
USE bank;
-- 创建 accounts 表
CREATE TABLE accounts (
account_id INT AUTO_INCREMENT PRIMARY KEY,
account_name VARCHAR(100) NOT NULL,
balance DECIMAL(10, 2) NOT NULL,
CONSTRAINT chk_balance CHECK (balance >= 0)
);
-- 插入初始数据
INSERT INTO accounts (account_name, balance) VALUES ('Alice', 1000.00);
INSERT INTO accounts (account_name, balance) VALUES ('Bob', 1000.00);
-- 设置会话隔离级别为 REPEATABLE READ
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 开始事务
START TRANSACTION;
-- 从 Alice 的账户减去 100 元
UPDATE accounts SET balance = balance - 100 WHERE account_name = 'Alice';
-- 向 Bob 的账户增加 100 元
UPDATE accounts SET balance = balance + 100 WHERE account_name = 'Bob';
-- 插入转账记录到 transactions 表
INSERT INTO transactions (from_account, to_account, amount)
SELECT a1.account_id, a2.account_id, 100
FROM accounts a1, accounts a2
WHERE a1.account_name = 'Alice' AND a2.account_name = 'Bob';
-- 提交事务,确保持久性
COMMIT;
-- 如果有任何错误,则回滚事务,确保原子性和一致性
-- ROLLBACK;
通过以上代码示例,展示了 MySQL 中如何实现 ACID 特性,确保数据库操作的可靠性和数据完整性。