了解锁机制
多版本并发控制 (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) |
SHARE | CREATE INDEX(非 CONCURRENTLY)命令 |
SHARE ROW EXCLUSIVE | CREATE TRIGGER 命令和一些 ALTER TABLE 命令 |
独家 | 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;