理解锁定
多版本并发控制 (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;