
# LOCK
#### 功能描述
LOCK TABLE获取表级锁。
当自动获取引用表的命令的锁时，DWS会始终使用限制最小的锁模式。如果用户需要一种更为严格的锁模式，可以使用LOCK命令。例如，某个应用是在Read Committed隔离级别上运行事务，并且需要保证表中的数据在事务运行期间保持稳定。为实现这个目的，则可以在查询之前对表使用SHARE锁模式进行锁定。这样将防止并发数据更改，并确保后续的查询可以读到已提交的持久化的数据。因为SHARE锁模式与任何写操作需要的ROW EXCLUSIVE模式冲突，并且LOCK TABLE name IN SHARE MODE语句将等到所有当前持有ROW EXCLUSIVE模式锁的事务提交或回滚后才能执行。因此，一旦获得该锁，就不会存在未提交的写操作，此外其他操作也只能等到该锁释放之后才能开始。
#### 注意事项
- LOCK TABLE只能在一个事务块的内部有用，因为锁在事务结束时就会被释放。出现在任意事务块外面的LOCK TABLE都会报错。
- 如果没有声明锁模式，缺省为最严格的模式ACCESS EXCLUSIVE。
- LOCK TABLE ... IN ACCESS SHARE MODE需要在目标表上有SELECT权限。所有其他形式的LOCK需要UPDATE和/或DELETE权限。
- 没有UNLOCK TABLE命令，锁总是在事务结束时释放。
- LOCK TABLE只处理表级的锁，因此那些带"ROW"字样的锁模式都是有歧义的。这些模式名字通常可理解为用户试图在一个被锁定的表中获取行级的锁。同样，ROW EXCLUSIVE模式也是一个可共享的表级锁。注意，只要是涉及到LOCK TABLE ，所有锁模式都有相同的语义，区别仅在于规则中锁与锁之间是否冲突，规则请参见[锁等级与冲突关系]。
 
#### 语法格式
```
LOCK [ TABLE ] {[ ONLY ] name [, ...]| {name [ * ]} [, ...]}
    [ IN {ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE | UPDATE EXCLUSIVE} MODE ]
    [ NOWAIT ] [LOCAL COORDINATOR ONLY];
```
 #### 锁等级与冲突关系
在DWS中，锁模式用于管理并发事务对资源的访问，以防止数据不一致和丢失。
[表1]列出了DWS支持的8种常规锁模式及其锁冲突关系：
 表1锁模式间的冲突关系 
| 锁模式名称                             | 锁等级 | 锁用途                                                                       | 冲突关系                   |
|:---|:---|:---|:---|
| 访问共享锁（AccessShareLock）            | 1   | SELECT语句，允许其他事务读取数据。                                                      | 8                      |
| 行共享锁（RowShareLock）                | 2   | SELECT FOR UPDATE或FOR SHARE，允许其他事务读取但阻止写入。                                | 7\|8                   |
| 行排他锁（RowExclusiveLock）            | 3   | INSERT、UPDATE、DELETE语句。                                                   | 5\|6\|7\|8             |
| 共享更新排他锁（ShareUpdateExclusiveLock） | 4   | VACUUM（非FULL）、ANALYZE、CREATE INDEX CONCURRENTLY、COMMENT ON，允许其他事务读取但阻止写入。 | 4\|5\|6\|7\|8          |
| 共享锁（ShareLock）                    | 5   | CREATE INDEX（非CONCURRENTLY），允许其他事务读取但阻止写入。                                | 3\|4\|6\|7\|8          |
| 共享行排他锁（ShareRowExclusiveLock）     | 6   | ROW SELECT...FOR UPDATE，类似RowExclusiveLock，但允许RowShareLock。               | 3\|4\|5\|6\|7\|8       |
| 排他锁（ExclusiveLock）                | 7   | 阻止RowShareLock或SELECT ... FOR UPDATE操作。                                   | 2\|3\|4\|5\|6\|7\|8    |
| 访问排他锁（AccessExclusiveLock）        | 8   | ALTER TABLE、DROP TABLE、VACUUM FULL，完全阻止其他事务读取和写入。                         | 1\|2\|3\|4\|5\|6\|7\|8 |
   
#### 参数说明
表2LOCK参数说明 
| 参数                                                          | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                     | 取值范围                               |
|:---|:---|:---|
| name  | 要锁定的表的名字，可以有模式修饰。 LOCK TABLE命令中声明的表的顺序就是上锁的顺序。                                                                                                                                                                                                                                                                                                                                           | 已存在的表名。                            |
| ONLY                                                        | 如果指定ONLY，则只有指定表被锁定；如果没有指定ONLY，则指定表及其所有继承表都会被锁定。 该参数仅为了兼容PG保留，DWS不支持继承表。                                                                                                                                                                                                                                                                                                                  | -                                  |
| ACCESS SHARE                                                | ACCESS锁只允许对表进行读取，而禁止对表进行修改。所有对表进行读取而不修改的SQL语句都会自动请求这种锁。例如，SELECT命令会自动在被引用的表上请求一个这种锁。                                                                                                                                                                                                                                                                                                                                                   | -                                  |
| ROW SHARE                                                   | ROW SHARE锁允许对表进行并发读取，禁止对表进行其他操作。 SELECT FOR UPDATE和SELECT FOR SHARE命令会自动在目标表上请求ROW SHARE锁（且所有被引用但不是FOR SHARE/FOR UPDATE的其他表上，还会自动加上ACCESS SHARE锁）。                                                                                                                                                                                                                                       | -                                  |
| ROW EXCLUSIVE                                               | 与ROW SHARE锁不同，ROW EXCLUSIVE允许并发读取表，也允许修改表中的数据。UPDATE，DELETE，INSERT命令会自动在目标表上请求这个锁（且所有被引用的其他表上还会自动加上的ACCESS SHARE锁）。通常情况下，所有会修改表数据的命令都会请求表的ROW EXCLUSIVE锁。                                                                                                                                                                                                                                                                              | -                                  |
| SHARE UPDATE EXCLUSIVE                                      | 这个模式保护一个表的模式不被并发修改，以及禁止在目标表上执行垃圾回收命令（VACUUM ）。 VACUUM（不带FULL选项），ANALYZE，CREATE INDEX CONCURRENTLY命令会自动请求这样的锁。                                                                                                                                                                                                                                                                           | -                                  |
| SHARE                                                       | SHARE锁允许并发的查询，但是禁止对表进行修改。 CREATE INDEX（不带CONCURRENTLY选项）语句会自动请求这种锁。                                                                                                                                                                                                                                                                                                                        | -                                  |
| SHARE ROW EXCLUSIVE                                         | SHARE ROW EXCLUSIVE锁禁止对表进行任何的并发修改，而且是独占锁，因此一个会话中只能获取一次。 任何SQL语句都不会自动请求这个锁模式。                                                                                                                                                                                                                                                                                                           | -                                  |
| EXCLUSIVE                                                   | EXCLUSIVE锁允许对目标表进行并发查询，但是禁止任何其他操作。 这个模式只允许并发加ACCESS SHARE锁，也就是说，只有对表的读动作可以和持有这个锁模式的事务并发执行。 任何SQL语句都不会在用户表上自动请求这个锁模式。然而在某些操作的时候，会在某些系统表上请求它。                                                                                                                                                                                           | -                                  |
| ACCESS EXCLUSIVE                                            | 这个模式保证其所有者（事务）是可以访问该表的唯一事务。 ALTER TABLE，DROP TABLE，TRUNCATE，REINDEX，CLUSTER，VACUUM FULL命令会自动请求这种锁。                                                                                                                                                                                                                                                                                        | 在LOCK TABLE命令没有明确声明需要的锁模式时，为缺省锁模式。 |
| UPDATE EXCLUSIVE                                            | UPDATE EXCLUSIVE锁允许并发（AUTO）VACUUM和（AUTO）ANALYZE，但不允许多个（AUTO）VACUUM并发。 说明： - 该参数仅8.2.1.200及以上集群版本支持。  - UPDATE EXCLUSIVE锁模式仅在VACUUM语法中使用。   | -                                  |
| NOWAIT                                                      | 声明LOCK TABLE不去等待任何冲突的锁释放，如果无法立即获取该锁，该命令退出并且发出一个错误信息。 在不指定NOWAIT的情况下获取表级锁时，如果有其他互斥锁存在的话，则等待其他锁的释放。                                                                                                                                                                                                                                                                                          | -                                  |
| LOCAL COORDINATOR ONLY                                      | 声明LOCK TABLE只在接收当前会话请求的CN上执行，而不会下发给其他CN和所有DN。该选项仅针对元数据的操作，以提高效率。 须知： - 该参数仅8.2.0.100以上集群版本支持。  - 当前仅支持ACCESS SHARE锁模式，其他锁模式会报错。           | -                                  |
   
#### 示例
准备数据：
```
DROP SCHEMA IF EXISTS tpcds CASCADE;
CREATE SCHEMA tpcds;
CREATE TABLE tpcds.reason
(
    r_reason_sk               bigint               not null,
    r_reason_id               char(16)             not null,
    r_reason_desc             char(100)
) 
 with (orientation = column)
distribute by replication;
```
向一个外键表上插入数据时，在有主键的表上使用SHARE锁：
```
START TRANSACTION;
LOCK TABLE tpcds.reason IN SHARE MODE;
SELECT r_reason_desc FROM tpcds.reason WHERE r_reason_sk=5;
COMMIT;
```
在执行删除操作时对一个有主键的表进行SHARE ROW EXCLUSIVE锁：
```
DROP TABLE IF EXISTS tpcds.reason_t1;
CREATE TABLE tpcds.reason_t1 AS TABLE tpcds.reason;
START TRANSACTION;
LOCK TABLE tpcds.reason_t1 IN SHARE ROW EXCLUSIVE MODE;
DELETE FROM tpcds.reason_t1 WHERE r_reason_desc IN(SELECT r_reason_desc FROM tpcds.reason_t1 WHERE r_reason_sk < 6 );
DELETE FROM tpcds.reason_t1 WHERE r_reason_sk = 7;
COMMIT;
```
删除表tpcds.reason_t1：
```
DROP TABLE tpcds.reason_t1;
```
查看表定义时，对表加ACCESS SHARE锁模式、限制范围是当前CN：
```
DROP TABLE IF EXISTS lock_test;
CREATE TABLE lock_test (a int, b int);
BEGIN;
LOCK TABLE lock_test IN ACCESS SHARE MODE LOCAL COORDINATOR ONLY;
SELECT pg_get_tabledef('lock_test');
END;
```
