ITPub博客

首页 > 数据库 > PostgreSQL > PostgreSQL:锁

PostgreSQL:锁

原创 PostgreSQL 作者:Ryan_Bai 时间:2020-12-14 22:20:15 0 删除 编辑

锁问题

  • 脏读:一个事务可以读到另一个事务中未提交的数据

  • 不可重复读:在一个事务没有结束时,另外一个事务也访问该同一数据集合,并做了 DML 操作。因此,在第一个事务两次读数据之间,读到的数据可能是不一样的

  • 幻读(丢失更新):一个事务的更新操作会被另一个事务的更新操作所覆盖,从而导致数据的不一致。

隔离级别

  • READ UNCOMMITTED

    • 允许事务查看其他事务所进行的未提交更改

    • 允许“脏”读、 不可重复读和虚读。

  • READ COMMITTED

    • 允许事务查看其他事务所进行的已提交更改

    • 不允许“脏”读。 但允许不可重复读和虚读。

    • 只支持二进制格式为 ROW 情况下

  • REPEATABLE READ

    • 确保每个事务的 SELECT 输出一致

  • SERIALIZABLE

    • 将一个事务的结果与其他事务完全隔离, 即一个事务所选的行不能由其他事务更改, 直到该事务完成为止。

    • 分布式事务常用。

锁机制

  1. 表级锁模式

    锁模式 描述
    ACCESS SHARE SELECT 命令将在所引用的表上加此类型的锁。通常只读取表而不修改表的查询都会请求这种锁模式
    ROW SHARE SELECT FOR UPDATE 和 SELECT FOR SHARE 命令会在目标表上加此类型的锁
    ROW EXCLUSIVE UPDATE、DELETE、INSERT 命令会自动在所修改的表上请求加这个锁。通常,修改表中数据的命令都是加这种锁
    SHARE UPDATE EXCLUSIVE 这个模式保护一个表,在模式改变和运行 VACUUM 并发、ANALYZE/CREATE INDEX CONCURR-ENTLY 命令请求这样的锁
    SHARE 这个模式可避免表的并发数据修改。CREATE INDEX (不带 CONCURRENTLY 选项)语句要求这样的锁模式
    SHARE ROW EXCLUSIVE 任何 PostgreSQL 命令都不会自动请求这个锁模式
    EXCLUSIVE 这个模式只允许并发 ACCESS SHARE 锁,也就是说,只有对表的度动作可以和持有这个锁的事务并发执行。任何 PostgreSQL 命令都不会用户表上自动请求这个锁模式。不过,在执行某些操作时,会在某些系统上请求这个锁。
    ACCESS EXCLUSIVE 这个模式只能保证只有一个人访问此表。ALTER TABLE、DROP TABLE、TRUNCATE、REINDEX、CLUSTER、VACUUM FULL 命令要求这样的锁。在 LOCK TABLE 命令中没有明确声明需要的锁模式时,它是默认锁模式
  2. 行级锁模式:只有两种,即“共享锁”和“排他锁”,或者可以说是“读锁”或“写锁”。而在 PostgreSQL 中不称其为“读锁”的原因是,由于有多版本的实现,所以实际读取数据时,并不会在行上执行任何锁。

表级锁命令

LOCK [ TABLE ] [ ONLY ] name [, ...] [ IN lockmode MODE ] [ NOWAIT ]
  • name:表名

  • lockmode:八种锁模式

  • NOWAIT:如果没有 NOWAIT 这个关键字时,当无法获得锁时,会一直等待,而如果加了 NOWAIT 关键字,在无法立即获取该锁时,此命令会立即退出并且发出一个错误信息。

行级锁命令

SELECT ...... FOR { UPDATE | SHARE } [ OF table_name [, ...] ] [ NOWAIT ] [...]

  •  [ OF table_name [, ...] ]:如果明确了表名字,那么只有这些被指定的表会被锁定,其他在 SELECT 中使用的表将不会被锁定。

  • 若主查询中引用了 WITH 查询时,WITH 查询中的表并不会被锁定。如果想锁定 WITH 查询内的表行,需要在 WITH 查询内指定 FOR UPDATE 或 FOR SHARE 关键字。

锁的查看

pg_locks 解释

列名称 列类型 引用 描述
locktype text 被锁定的对象类型
database oid pg_database.oid 锁定对象之数据库的 OID,如果对象是一个共享对象,不属于任何一个数据库,此值为 0,如果对象是“transaction ID”,此值为空
relation oid pg_class.oid 如果对象不是表或只是表的一部分,则此值为 null,否则此值是表的 OID
page integer 表中的页号,如果对象不是表行 (tuple) 或表页 (relation page),则此值为 null
tuple smallint 页内的行号 (tuple),如果对象不是表行 (tuple),则此值为空
virtualxid text 是一个虚拟事务 ID (ID of a transaction),如果对象不是虚拟事务,则此值为 null
transactionid xid 事务 ID (ID of a transaction),如果对象不是事务 ID,此值则为 null
classid oid pg_class.oid 包含该对象的系统目录 (system catalog) 的 OID,如果对象不是通常的数据库对象,则此值为空
objid oid any OID column 对象在系统目录(system catalog) 中的 OID,如果对象不是通常的数据库对象,则此值为空。对于 advisory locks,此字段用于区别两类 key 空间(1 表示 int8 的 key,2 表示 two int4 的 key)
objsubid smallint 如果对象是表列 (table column),此列的值为列号,这时“classid”和“objid”指向表,在其他的数据库类型中,此值为 0;如果不是数据库对象,则此值为 null
virtualtransaction text 持有或等待这把锁的虚拟事务的 ID (Virtual ID of the transaction)
pid integer 持有或等待这把锁的服务进程的 pid。如果此锁是被一个两阶段的事务持有,则此值为 null
mode text 锁的模式名称
granted boolean 如果锁已被持有,此之为“True”;如果等待获得此锁,则此值为“False”

事务 ID 字段详解

  • transactionid-->xid:普通事务 ID

  • virtualxid-->vxid:只读事务 ID

  • virtualtransaction:表示持有锁或等待锁 session 的虚拟事务 ID。

常用语句

SELECT locktype,
       relation::regclass as rel,
       page||','||tuple as ctid,
       virtualxid as vxid,
       transactionid as xid,
       virtualtransaction as vxid2,
       pid,
       mode,
       granted
  FROM pg_locks;

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31490526/viewspace-2742209/,如需转载,请注明出处,否则将追究法律责任。

上一篇: PostgreSQL:事务
请登录后发表评论 登录
全部评论
Oracle ACE Associate; OCMU 用户组成员; Oracle 10g OCE、OCA、OCP; Oracle 11g OCP、OCM; MySQL 5.6 OCP; Oracle 11g OCP讲师; PostgreSQL PGCE 获得者;

注册时间:2017-09-18

  • 博文量
    226
  • 访问量
    261362