📚 目录

  1. 概述
  2. 锁的基本类型
  3. LOCK 命令的基本语法
  4. 锁的使用示例
  5. 死锁和避免死锁
  6. 参考资料

🛠️ 概述

在 PostgreSQL 中,锁(Lock) 用于确保多个事务并发访问数据库时,数据的一致性和完整性。锁机制确保在执行某些操作(如更新、删除等)时,其他事务不能同时修改相同的数据。PostgreSQL 提供了多种类型的锁,以便在并发操作中提供不同级别的控制。

🔐 锁的基本类型

PostgreSQL 中有几种常见的锁类型,以下是几种主要的锁:

  1. 行级锁(Row-Level Lock): 行级锁只锁定某一行数据,允许其他事务对表中的其他行进行操作。行级锁通常用于更新或删除操作。 常用锁类型:
    • FOR UPDATE:锁定被查询到的行,防止其他事务修改或删除这些行。
    • FOR NO KEY UPDATE:类似于 FOR UPDATE,但是允许其他事务对锁定的行插入新行。
    • FOR SHARE:允许其他事务读取这些行,但不允许修改。
    • FOR KEY SHARE:类似于 FOR SHARE,但允许在锁定行上插入新行。
  2. 表级锁(Table-Level Lock): 表级锁锁定整个表,防止其他事务对表中的任何数据进行操作。这种锁通常用于更广泛的操作,例如添加或删除表。 常用锁类型:
    • ACCESS SHARE:最轻的锁类型,仅用于查询操作。允许其他事务执行查询。
    • ROW EXCLUSIVE:在修改表时使用,阻止其他事务执行对该表的 INSERTUPDATEDELETE 操作。
    • SHARE:用于在进行读取时锁定表,并且防止其他事务修改该表。
    • EXCLUSIVE:表级独占锁,其他事务不能修改表。
    • ACCESS EXCLUSIVE:最强的锁类型,完全锁定整个表,防止其他事务进行任何操作。
  3. 元数据锁(Metadata Lock): 用于锁定数据库模式的元数据,防止在修改表结构(例如 ALTER TABLE)时,其他事务访问表结构。

📝 LOCK 命令的基本语法

使用 LOCK 命令可以显式地锁定一个表或其他数据库对象。

语法:

LOCK TABLE table_name IN lock_mode MODE;

  • table_name:要锁定的表名。
  • lock_mode:要使用的锁类型,可以是多种锁模式之一,如 ACCESS SHAREROW EXCLUSIVE 等。

示例:

LOCK TABLE employees IN EXCLUSIVE MODE;

此命令会对 employees 表应用 EXCLUSIVE 锁,防止其他事务修改或访问该表。


📝 锁的使用示例

示例 1:行级锁

假设有两个事务分别执行以下操作:

事务 1

BEGIN;

SELECT * FROM employees WHERE employee_id = 1 FOR UPDATE;

事务 2

BEGIN;

SELECT * FROM employees WHERE employee_id = 1 FOR UPDATE;

  • 在事务 1 中,FOR UPDATE 会锁定查询到的行,并防止其他事务修改它。
  • 如果事务 2 试图在事务 1 提交之前获取相同的行,它将会被阻塞,直到事务 1 提交或回滚。

示例 2:表级锁

如果需要锁定整个表,可以使用以下命令:

LOCK TABLE employees IN EXCLUSIVE MODE;

此命令会对 employees 表加锁,防止其他事务修改表的内容。


🛑 死锁和避免死锁

死锁(Deadlock) 是指两个或更多的事务相互等待对方持有的资源,从而导致无法继续执行下去的情况。例如,事务 1 持有表 A 的锁,并等待事务 2 释放表 B 的锁,而事务 2 持有表 B 的锁,并等待事务 1 释放表 A 的锁。

死锁的避免:

  1. 保持事务简短:避免长时间持有锁,确保事务尽可能快地完成。
  2. 一致的锁顺序:确保所有事务都以相同的顺序获取锁,以减少死锁的风险。
  3. 适当使用锁的粒度:避免过度使用表级锁,使用行级锁可以减少锁竞争的可能性。

PostgreSQL 内部有一个死锁检测机制,会在发现死锁时自动中断一个事务,并返回死锁错误。


📘 参考资料