理解锁定

已完成

多版本并发控制 (MVCC) 为大多数方案提供了适当的并发设置。 但如果应用程序需要特定的锁,以精确控制哪些行受到影响,并且具有特定锁级别,则显式锁定模式将启用此精细控制。

在 Azure Database for PostgreSQL 中,有三种类型的显式锁定:表级锁定、行级锁定和页级锁定。 初始事务请求锁定,如果接受,请求的锁将成为现有锁。 如果另一个事务尝试对同一数据执行锁定,则仅当它与原始事务不冲突时,才会授予该锁。

例如,两个事务可以使用 SELECT 语句同时查询相同的数据。 这些请求将使用 ACCESS SHARE 锁,并且两个操作都会得到允许。 在另一种方案中,一个事务使用 SELECT 语句和 ACCESS SHARE 锁定查询数据,但同时另一个事务尝试删除同一个表。 删除表需要 ACCESS EXCLUSIVE 锁,但在此方案中不会被授予。

表级别的锁

表级别锁定会使整个表锁定,即使其名称中有 ROW。 如果修改表本身,则可能需要锁定整个表,这可能比实施许多行级锁定更高效。

Azure Database for PostgreSQL 中存在八种类型的表级锁,下面是用于获取这些锁的 SQL 命令:

锁定模式 获取方
ACCESS SHARE SELECT 命令
ROW SHARE SELECT FOR UPDATE 和 SELECT FOR SHARE 命令
ROW EXCLUSIVE UPDATE、DELETE 和 INSERT 命令
SHARE UPDATE EXCLUSIVE ANALYZE、CREATE INDEX CONCURRENTLY、CREATE STATISTICS、COMMENT ON、REINDEX CONCURRENTLY 命令、某些 ALTER INDEX 和 ALTER TABLE 命令,以及 VACUUM(非 FULL)
共享 CREATE INDEX(非 CONCURRENTLY)命令
SHARE ROW EXCLUSIVE CREATE TRIGGER 命令和一些 ALTER TABLE 命令
EXCLUSIVE REFRESH MATERIALIZED VIEW CONCURRENTLY 命令
ACCESS EXCLUSIVE DROP TABLE、REINDEX、TRUNCATE、CLUSTER、REFRESH MATERIALIZED VIEW(非 CONCURRENTLY)命令、大多数 ALTER INDEX 和 ALTER TABLE 命令以及 VACUUM FULL

每种类型的现有锁都会阻止获取其他请求的锁。 下表列出了哪些锁会阻止获取其他锁:

-- 现有 ACCESS SHARE 现有 ROW SHARE 现有 ROW EXCLUSIVE 现有 SHARE UPDATE EXCLUSIVE 现有 SHARE 现有 SHARE ROW EXCL 现有 EXCLUSIVE 现有 ACCESS EXCLUSIVE
请求的 ACCESS SHARE 已阻止
请求的 ROW SHARE 已阻止 已阻止
请求的 ROW EXCLUSIVE 已阻止 已阻止 已阻止 已阻止
请求的 SHARE UPDATE EXCLUSIVE 已阻止 已阻止 已阻止 已阻止 已阻止
请求的 SHARE 已阻止 已阻止 已阻止 已阻止 已阻止
请求的 SHARE ROW EXCLUSIVE 已阻止 已阻止 已阻止 已阻止 已阻止 已阻止
请求的 EXCLUSIVE 已阻止 已阻止 已阻止 已阻止 已阻止 已阻止 已阻止
请求的 ACCESS EXCLUSIVE 已阻止 已阻止 已阻止 已阻止 已阻止 已阻止 已阻止 已阻止

行级锁定

行级别锁定更精细,只会影响正在访问同一行的另一个事务。 这种锁类型可以提高并发性,但获取和删除许多锁会对性能产生不良影响。 行级锁定由 PostgreSQL 自动获取,不会手动应用。

Azure Database for PostgreSQL 中存在四种类型的行级锁,它们的获取由需要阻止的其他锁类型决定:

-- 现有 FOR KEY SHARE 现有 FOR SHARE 现有 FOR NO KEY UPDATE 现有 FOR UPDATE
请求的 FOR KEY SHARE 已阻止
请求的 FOR SHARE 已阻止 已阻止
请求的 FOR NO KEY UPDATE 已阻止 已阻止 已阻止
请求的 FOR UPDATE 已阻止 已阻止 已阻止 已阻止

页级锁定

页面级锁定会影响数据页,通常由多行组成。 尽管 PostgreSQL 进程使用页级锁,但应用程序开发人员通常不需要这种类型的锁。

手动应用锁定并查看当前锁定

若要手动应用表级锁定,可以将 LOCK 命令与所需的锁定模式一起使用。 LOCK 命令必须位于事务中,事务完成后会释放锁定。 例如:

BEGIN TRANSACTION;
LOCK TABLE humanresources.department IN ROW EXCLUSIVE MODE;
COMMIT;

若要查看当前在数据库上保留的锁定,请使用 pg_locks。 例如,要查看所有当前锁定,请使用以下命令:

SELECT * FROM pg_locks;