PostgreSQL 事务与并发控制

当多个事务并发执行时, 即使每个 单独的事务 都正确执行, 数据库的一致性也可能被破坏.
为了控制 并发事务 之间的相互影响, 解决并发可能带来的数据不一致问题, 数据库的并发控制系统 引入了 基于锁的并发控制(Lock-Based Concurrency Control) 和 基于多版本的并发控制机制 MVCC (Mult-Version Concurrency Control).

1 事务

事务 是 数据库系统 执行过程中最小的逻辑单位.
事务被提交时, 数据库管理系统 要确保一个事务中的 所有操作都成功完成, 并在数据库中永久保存; 如果一个事务中的一部分没有成功, 则系统会把数据库回滚到操作执行之前的状态.

事务有 4 个特性:

  1. 原子性(Atomicity): 一个事务的所有操作, 要么全部执行, 要么全部不执行.
  2. 一致性(Consistency): 保证数据库从一个正确的状态(满足约束)到另一个正确的状态.
  3. 隔离性(Isolation): 事务并发执行时, 可能会交叉执行, 从而导致不一致的情况发生. 确保事务并发执行时, 每个事务都感觉不到有其他事务在并发的执行.
  4. 持久性(Durability): 一个事务完成后, 它对数据库的改变应该永久保存在数据库中.

这 4 个特性也称之为 ACID.
事务一致性 由主键, 外键这类约束保证;
持久性 由预写日志(WAL) 和数据库管理系统的恢复子系统保证;
原子性隔离性 由 事务管理器 和 MVCC 来控制.

1.1 事务并发引发的问题

如果所有的事务都按照顺序执行, 那么执行时间就没有重叠交错, 也就不会有并发问题.

PostgreSQL 把 事务并发 导致的问题 总结为:

  1. 脏读(Dirty read), 事务A 读取了 事务B 已经修改但是还没有提交的数据.
  2. 不可重复读(Non-repeatable read), 事务A 读取了数据X; 然后 事务B 修改了数据X 并提交; 然后事务A 再次读取数据X. 对于事务A来说, 两次读取结果不一致. 这种现象就是 不可重复读.
  3. 幻读(Phantom read), 一个事务的两次执行相同的查询, 结果集数目不一致. 幻读 可以 认为是 受 INSERTDELETE 影响 不可重复读 的特例.
  4. 序列化异常(Serialization anomaly), 在可重复读情况下, 可能会出现序列化异常. 比如 X=1 事务A 执行 X++ 操作; 在事务A 提交之前, 事务B 修改 X=10 并提交成功; 由于事务A 是可重复读的, 事务A 看到的数据还是 X=1. 这就发生了序列化异常: 先执行事务A 和 先执行事务B 的结果是不一样的.

1.2 ANSI SQL 标准的事务隔离级别

为了避免 事务与事务之间 并发执行 引发的副作用, 最简单的方法是 串行地 执行事务, 但是 串行化 会大幅降低系统吞吐量, 降低系统资源利用率.

为此, ANSI(American National Standards Institute, 美国国家标准学会) SQL 标准定义了 4 类事务隔离级别:

  1. 读未提交(Read Uncommitted): 所有事务都可以看到其他未提交事务的执行结果. 可以看到 读未提交 允许 脏读 发生, 脏读是非常危险的, 查询结果非常不可控, 所以 读未提交 事务隔离级别 很少实际应用.
  2. 读已提交(Read Committed): 这是 PostgreSQL 默认的隔离级别, 它满足了 一个事务 只能看到 已提交事务 对关联数据所做的改变.
  3. 可重复读(Repeatable Read): 确保同一个事务在看到的数据内容是一致的.
  4. 可序列化(Serializable): 最高的隔离级别, 通过强制事务排序, 使之不可能相互冲突, 从而解决幻读问题.

下表是 ANSI SQL 标准定义的事务隔离级别 与 读现象 的关系:

隔离级别脏读不可重复读幻读
Read Uncommitted可能可能可能
Read Committed不可能可能可能
Repeatable Read不可能不可能可能
Serializable不可能不可能不可能

对于同一个事务来说, 不同的事务隔离级别执行结果可能不同.
事务隔离级别越高, 越能保证数据的完整性和一致性, 但增加了阻塞其他事务的概率, 并发性能越差, 吞吐量也越低.

对于大多应用程序, 优先考虑 Read Committed 隔离级别, 它可以避免脏读, 而且有较好的并发性能. 尽管它会导致 不可重复读, 幻读问题, 这类问题可以由应用程序加锁来控制.

2 PostgreSQL 的事务隔离级别

下面的表格是 PostgreSQL 中不同的事务隔离级别 与 读现象 的关系:

隔离级别脏读不可重复读幻读序列化异常
Read Uncommitted不可能可能可能可能
Read Committed不可能可能可能可能
Repeatable Read不可能不可能不可能可能
Serializable不可能不可能不可能不可能

PostgreSQL 只实现了 3 种 隔离级别. 在 PostgreSQL 中, Read Uncommitted 和 Read Committed 是一样的.

2.1 查看和设置数据库的事务隔离级别

查看 PostgreSQL 全局事务隔离级别:

SELECT name, setting 
FROM pg_settings 
WHERE name = 'default_transaction_isolation';

-- 或者
SELECT  current_setting('transaction_isolation');

修改全局的事务隔离级别:

ALTER SYSTEM 
SET default_transaction_isolation TO  'REPEATABLE READ';

-- 修改之后 reload 实例使之生效
SELECT pg_reload_conf();

3 PostgreSQL 的并发控制

为了保证事务的隔离性, 系统必须对 并发事务 之间的相互作用加以控制, 这就是数据库管理系统的 并发控制器 要做的事情.

并发控制模型有 基于锁的并发控制(Lock-Based Concurrency Control)基于多版本的并发控制(Multi-Version Concurrency Control).

3.1 基于锁的并发控制

为了解决并发问题, 数据库引入了 “锁” 的概念.
有两种锁类型: 排它锁(Exclusive locks, X 锁) 和 共享锁(Share locks, S 锁).

加锁 对象的大小称为 锁粒度(granularity).
加锁的对象可以是 逻辑单元: 属性值, 属性值的集合, 关系, 索引项, 甚至整个数据库;
也可以是物理单元: 页(数据页或索引页), 物理记录等.

3.2 基于多版本的并发控制(MVCC)

MVCC通过把数据项的旧值保存在系统中, 来保证并发事务的正确性.

一般把 基于锁的并发控制 称为 悲观机制; 把 MVCC 称为 乐观机制.
这是因为 锁 是一种预防性机制, 写会阻塞读, 读会阻塞写; MVCC 是一种后验性机制, 等到提交的时候才检查是否有冲突.

由于 MVCC 读写不会相互阻塞, 避免了大粒度和长时间的锁定, 能更好地适应 对读的响应速度 和 并发性要求高的场景, 常见的数据库如 Oracle, PostgreSQL, MySQL(Innodb) 都使用 MVCC 做 并发控制机制.

在 MVCC 中, 每一个写操作会创建一个新的版本. 当事务发起一个读操作时, 并发控制器选择一个版本读, 连同版本号一起读出, 在更新时对此版本号加一.

PostgreSQL 为每个事务分配一个递增的, int32 整型 数作为 唯一的事务ID, 即 xid.
PostgreSQL 内部数据结构中, 每个元组(行记录) 有 4 个与事务可见性相关的 隐藏列:

  1. xmin, 创建该行数据的 xid;
  2. xmax, 删除改行的xid;
  3. cmin, 插入该元组的命令在事务中的命令序列号;
  4. cmax, 删除该元组的命令在事务中的命令序列号.

Reference

[1]. PostgreSQL 实战 - 谭峰

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PostgreSQL 是一个功能强大的关系型数据库管理系统,在处理数据库事务并发控制方面有着很多特性和机制。下面是关于 PostgreSQL 数据库事务并发控制的一些重要信息: 1. 数据库事务事务是一组操作的逻辑单元,要么全部执行成功,要么全部回滚。在 PostgreSQL 中,事务的开始和结束通过 BEGIN 和 COMMIT 或 ROLLBACK 语句来定义。默认情况下,每个 SQL 语句都在单独的事务中执行,但你可以使用显式的 BEGIN 和 COMMIT 指令来控制事务的边界。 2. 并发控制并发控制是指在多个用户同时访问数据库时,保证数据的一致性和正确性。PostgreSQL 使用多版本并发控制(MVCC)机制来实现并发控制。MVCC 使用了版本号(或时间戳)来跟踪事务的可见性和一致性。 3. 锁机制:PostgreSQL 使用锁来控制并发访问。锁可以对表、行或其他数据库对象进行加锁,以防止其他事务对其进行修改或访问。锁分为共享锁和排它锁,用于控制读取和写入操作之间的冲突。 4. 事务隔离级别:PostgreSQL 支持四种事务隔离级别,分别是读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。这些隔离级别提供了不同的并发控制策略,可以根据应用程序的需求进行配置。 5. 并发控制配置:PostgreSQL 提供了多种配置选项来调整并发控制的性能和行为。你可以通过修改配置文件或使用 ALTER SYSTEM 命令来更改这些选项。一些常见的配置选项包括 max_connections(最大连接数)、max_locks_per_transaction(每个事务最大锁数)和deadlock_timeout(死锁超时时间)等。 总而言之,PostgreSQL 提供了强大的数据库事务并发控制机制,通过锁机制、MVCC 以及事务隔离级别来处理并发操作和保证数据的一致性。这些特性使得 PostgreSQL 成为处理高并发场景下数据操作的理想选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值