表锁有 SHARE 和 EXCLUSIVE 这两种, 就是读写锁的意思。 加 SHARE 锁相当于加了读
锁, 表中的内容就不能变化了。 可为多个事务加上此锁, 只要任意一个用户不释放此读锁,
其他用户就不能修改这个表。 加 EXCLUSIVE 锁相当于加了写锁, 这时别的进程既不能写
也不能读这条数据。 但是, 后来数据库又加了多版本的功能。 有了该功能后, 如果改某一
行的数据, 实际上并没有改变原先那行数据, 而是另复制出了一个新行, 修改都在新行上进
行, 事务不提交, 别人是看不到这条数据的。 由于原先的那行数据没有变化, 在修改过程
中, 读数据仍然可以读到原有数据, 这样就没有必要阻塞其他用户读数据了。 在多版本功能
下, 除了以前的 SHARE 锁和 EXCLUSION 锁外, 还增加两个锁, 一个叫作“ACCESS
SHARE”,表明加上这个锁, 即使是正在修改数据的情况下也允许读数据, 另一个锁叫作
“ACCESS EXCLUSION”, 意思是即使有多版本的功能, 也不允许访问数据。
加表锁的对象是表, 由加锁的范围太大会导致并发不高, 于是提出了行级锁的概念, 但行锁
与表锁之间会产生冲突, 这时就需要有一种机制来描述行锁与表锁之间的关系。 在
PostgreSQL 中, 使用 ROW SHARE、 ROW EXCLUSIVE 这两个锁来解决这一问题,方
法就是当需要修改表中数据时, 需要先在表上加一种锁, 表示即将在表上加共享锁或排它锁。
ROW SHARE、ROW EXCLUSIVE 互相之间不会发生冲突, 因为它们都只是想要做什么
但还没有真做, 所以是可以兼容的。就像 MySQL 中的 意向锁:共享意向锁(IS) 和排它意
向锁(IX) 。
意向锁用于协调表锁与行锁之间的关系,用于保护较低资源级别上的锁,即说明下层节点已经
被加了锁。当进程想要锁定或修改某表上的某一行时,它会在这一行上加上行锁。但在加行锁
之前,它还需要在这张表上加上一把意向锁,表示自己将会在表中的若干行上加锁。
ROW EXCLUSIVE 之间是不会冲突的, 这时需要一种严格的锁, 就是这种锁自身也会冲
突, 这种锁在 PostgreSQL 中就叫“SHARE UPDATE EXCLUSIVE”。 不带 FULL 选项的
VACUUM、 CREATE INDEX CONCURRENTLY 命令都请求此类型的锁。
在 PostgreSQL 中还有一种锁, 称为“SHARE ROW EXCLUSIVE”, 这种锁可以看成是同
时加了“SHARE”锁和“ROW EXCLUSIVE”锁的结果, PostgreSQL 命令都不会自动请求这
种锁模式, 也就是说, PostgreSQL 内部目前不会使用这种锁。
总结:
PostgreSQL 中有 8 种表锁, 最普通的共享锁“SHARE”和排它锁“EXCLUSIVE”, 因为多
版本的原因, 修改一条数据的同时允许读数据, 所以为了处理这种情况, 又加了两种锁
“ACCESS SHARE”和“ACESS EXCLUSIVE”, 所以锁中的“ACCESS”这个关键字是与多
版本读相关的。 此外, 为了处理表锁和行锁之间的关系, 于是有了 ROW SHARE 和 ROW
EXCLUSIVE, 这时又加了两种锁。 这样就有了 6 种锁。 由于 ROW SHARE 之间不会产
生冲突, 而且 ROW EXCLUSIVE 之间也不会产生冲突, 于是又需要更严格一些的锁,这
样就产生了 SHARE UPDATE EXCLUSIVE 和 SHARE ROW EXCLUSIVE 两种锁, 于
是就有了 8 种锁。
表锁命令
在 PostgreSQL 中, 显式地在表上加锁的命令为“LOCK TABLE”, 此命令的语法如下:
LOCK [ TABLE ] [ ONLY ] name [, ...] [ IN lockmode MODE ] [ NOWAIT ]
其中各参数的说明如下。
评论