CodeGym /课程 /SQL SELF /隔离级别 READ COMMITTED

隔离级别 READ COMMITTED

SQL SELF
第 40 级 , 课程 0
可用

咱们来搞清楚 READ COMMITTED 这个隔离级别到底干了啥。它的名字其实就暗示了:你在事务里读到的内容,都是别的事务已经“提交”过的。就像现实生活里,我们只相信那些已经被官方记录下来的八卦。

说正经点,这个级别保证了事务不会看到其他事务还没提交的更改。这就解决了“脏读”(Dirty Read)的问题。不过要注意,你读到的数据可能会变——如果别的事务在你两次查询之间提交了更改。这就有了“不可重复读”(Non-Repeatable Read)的风险。

在 PostgreSQL 里,READ COMMITTED 是默认隔离级别。就像默认模式一样——你啥都不用特意设置,直接用就行。

隔离级别 READ COMMITTED 的使用示例

咱们来看看实际操作是啥样。假设有个 accounts 表,里面存着用户和他们的余额:

CREATE TABLE accounts (
    account_id SERIAL PRIMARY KEY,
    account_name TEXT NOT NULL,
    balance NUMERIC(10, 2) NOT NULL
);

INSERT INTO accounts (account_name, balance)
VALUES ('Alice', 1000.00), ('Bob', 500.00);

现在想象一下下面这个场景。Session 1 和 Session 2 —— 我们故事里的两个主角,都在操作 accounts 表。流程是这样的:

Session 1:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_name = 'Alice';
-- 还没 COMMIT 或 ROLLBACK。

这时候,Alice 的 balance 暂时被减了 100,但结果还没提交。

Session 2:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

BEGIN;
SELECT balance FROM accounts WHERE account_name = 'Alice';

结果:Session 2 看到 Alice 的余额还是 1000.00,因为 Session 1 的事务还没结束(还没 COMMIT)。READ COMMITTED 保护我们不被“脏读”坑到。

Session 1 结束事务:

COMMIT;

现在 Alice 的余额更新了,数据库里已经是 900.00

Session 2 再查一次:

SELECT balance FROM accounts WHERE account_name = 'Alice';

结果:Session 2 现在看到 Alice 的新余额——900.00。注意,这次结果和上次查的不一样,上次是 1000.00。这就是“不可重复读”的问题。

什么时候用 READ COMMITTED

READ COMMITTED 隔离级别就是性能和一致性的平衡点。有些场景它用起来特别爽:

  1. 简单的 CRUD 操作: 你只是单纯地查查、改改数据,没有啥复杂的关联。

  2. 批量更新记录: 比如批量改表里的数据,想马上看到已经提交的更改。

  3. 处理事务: 比如支付系统,只让用户看到已经确认过的数据。

不过如果你要做复杂的分析查询,或者数据量特别大,可能得考虑别的隔离级别,比如 REPEATABLE READ

READ COMMITTED 的优缺点

READ COMMITTED 隔离级别算是个黄金中间值。它能保护你不被脏数据坑:你不会看到别的事务刚开始但还没结束的更改。也就是说,没人能读到“半成品”信息,这些信息随时可能被回滚掉。

这个模式比更严格的隔离级别(REPEATABLE READSERIALIZABLE)快,因为它不需要复杂的锁和额外的检查。它够轻便,也挺靠谱——所以才是默认选项,日常用用完全没问题。

虽然它能防止脏读,READ COMMITTED 还是挡不住:

  • “不可重复读”(Non-Repeatable Read):如果别的事务在你两次查询之间改了数据,你读到的值就变了。
  • “幻读”(Phantom Read):别的事务可能加了新行,影响了你的查询结果。

READ COMMITTED 时的小建议

一定要结束事务:别忘了用 COMMITROLLBACK,不然容易锁表出问题。

确认隔离级别够用:如果你需要保证事务期间数据不会变,考虑用 REPEATABLE READ

用好索引:这样 PostgreSQL 查数据、改数据都更快。

示例:订单处理

假设有个 orders 表,存着订单信息:

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    customer_name TEXT NOT NULL,
    status TEXT NOT NULL DEFAULT 'pending'
);

INSERT INTO orders (customer_name, status)
VALUES ('Alice', 'pending'), ('Bob', 'pending');

我们想把所有状态是 "pending" 的订单状态改掉:

BEGIN;
SELECT * FROM orders WHERE status = 'pending';
UPDATE orders SET status = 'completed' WHERE status = 'pending';
COMMIT;

如果在你操作的过程中,别的事务加了一个新的 "pending" 订单并且 COMMIT 了,你的事务是不会处理到这条新记录的,因为它是在你开始读之后才加进来的。

这就是“幻读”的例子。如果你想避免这种情况,就得用 SERIALIZABLE

READ COMMITTED 隔离级别是大多数数据库(包括 PostgreSQL)的默认选择。它能防止脏读,所以很适合大多数常规操作。但如果你有更高的一致性要求,可能得用更严格的隔离级别。隔离级别怎么选,还是得看你具体的需求和性能要求。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION