第六十一章 SQL命令 LOCK
锁表
大纲
LOCK [TABLE] tablename IN EXCLUSIVE MODE [WAIT seconds]
LOCK [TABLE] tablename IN SHARE MODE [WAIT seconds]
参数
tablename
- 要锁定的表的名称。
Tablename
必须是已经存在的表。
表名可以是限定的(schema.table
),也可以是非限定的(table
)。
非限定表名接受默认模式名。
模式搜索路径被忽略。IN EXCLUSIVE MODE
/IN SHARE MODE
-IN EXCLUSIVE MODE
关键字短语创建一个常规的IRIS锁。
IN SHARE MODE
关键字短语创建一个共享的IRIS锁。WAIT seconds
- 可选-一个整数,指定在超时前尝试获取锁的秒数。
如果省略,则应用系统默认超时时间。
描述
LOCK
和LOCK TABLE
是同义词。
LOCK
命令显式锁定SQL表。
此表必须是已存在的表,对其具有必要的特权。
如果tablename
是一个不存在的表,LOCK
会失败并出现编译错误。
如果tablename
是临时表,则命令执行成功,但不执行任何操作。
如果tablename
是视图,则命令失败,并出现SQLCODE -400
错误。
UNLOCK
命令用来反转LOCK
操作。
显式LOCK
将保持有效,直到针对同一模式发出显式UNLOCK
,或者直到进程终止。
可以使用LOCK
多次锁定一个表;
必须显式解锁表,解锁次数为表被显式锁定的次数。
每个UNLOCK
必须指定与相应LOCK相同的模式。
权限
LOCK
命令是一个特权操作。
在使用LOCK IN SHARE MODE
之前,进程必须对指定的表拥有SELECT
特权。
在使用LOCK IN EXCLUSIVE MODE
之前,进程必须对指定的表拥有INSERT
、UPDATE
或DELETE
特权。
对于IN EXCLUSIVE MODE
, INSERT
或UPDATE
特权必须在表的至少一个字段上。
未能持有足够的特权将导致SQLCODE -99
错误(特权违反)。
可以通过调用%CHECKPRIV
命令来确定当前用户是否具有必要的特权。
可以通过调用$SYSTEM.SQL.Security.CheckPrivilege()
方法来确定指定的用户是否具有必要的特权。
这些特权是获取锁所必需的;
它们没有定义锁的性质。
IN EXCLUSIVE MODE
锁阻止其他进程执行INSERT
、UPDATE
或DELETE
操作,而不管锁持有者是否拥有相应的特权。
锁模式
LOCK
支持SHARE
和EXCLUSIVE
两种模式。
这些锁模式是相互独立的。
可以对同一个表应用SHARE锁和EXCLUSIVE
锁。
EXCLUSIVE
模式下的锁只能通过EXCLUSIVE
模式下的UNLOCK
解锁。
“SHARE”
模式下的锁只能通过“UNLOCK”
解锁。
LOCK mytable IN SHARE MODE
可以防止其他进程对mytable
发出EXCLUSIVE
锁,或者调用DDL
操作,比如DROP TABLE
。LOCK mytable IN EXCLUSIVE MODE
可以防止其他进程对mytable
发出EXCLUSIVE
锁或SHARE
锁,也可以防止其他进程对mytable
执行插入、更新或删除操作,或者调用DDL操作(如DROP TABLE
)。
LOCK
允许对表的读访问。
这两种LOCK
模式都不能阻止其他进程在READ UNCOMMITTED
模式(默认的SELECT
模式)下对表执行SELECT
操作。
锁冲突
- 如果一个表在
EXCLUSIVE
模式下已经被其他用户锁定,那么在任何模式下都不能锁定它。 - 如果一个表在
SHARE
模式下已经被其他用户锁定,也可以在SHARE
模式下锁定该表,但不能在EXCLUSIVE
模式下锁定该表。
这些锁冲突产生SQLCODE -110
错误,并生成%msg
,如下所示:
锁超时
LOCK
尝试获取指定的SQL表锁,直到超时。
当超时发生时,LOCK
生成SQLCODE -110
错误。
- 如果指定了
WAIT
秒数,SQL表锁定超时将在该秒数过后发生。 - 否则,当当前进程的SQL超时结束时,SQL表锁定超时发生。
可以使用$SYSTEM.SQL.Util.SetOption()
方法的ProcessLockTimeout
选项为当前进程设置锁定超时。
还可以使用带有LOCK_TIMEOUT
选项的SQL命令set OPTION
为当前进程设置锁定超时。
(SET OPTION
不能从SQL Shell
中使用。)
当前进程的SQL锁定超时默认为系统范围的SQL锁定超时。 - 否则,SQL表锁定超时发生时,系统范围的SQL超时。系统范围的缺省值是10秒。设置全系统锁定超时时间有两种方式:
- 使用
$SYSTEM.SQL.Util.SetOption()
方法的LockTimeout
选项。
这将立即更改新进程的系统范围锁定超时默认值,并将当前进程的ProcessLockTimeout
重置为这个新的系统范围值。
设置系统范围的锁超时对当前运行的其他进程的ProcessLockTimeout
设置没有影响。 - 使用管理门户,选择系统管理、配置、SQL和对象设置、SQL。
查看和编辑当前的锁定超时(秒)设置。
这将更改在保存配置更改后启动的新进程的系统范围锁定超时默认值。
它对当前运行的进程没有影响。
- 使用
要返回当前系统范围的锁超时值,调用$SYSTEM.SQL.Util.GetOption("LockTimeout")
方法。
要返回当前进程的锁超时值,请调用$SYSTEM.SQL.Util.GetOption("ProcessLockTimeout")
方法。
事务处理
LOCK
操作不是事务的一部分。
回滚发出LOCK
的事务不会释放锁。
UNLOCK
可以定义为在当前事务结束时发生,或者立即发生。
其他锁定操作
许多DDL操作,包括ALTER TABLE
和DELETE TABLE
,都需要独占表锁。
INSERT
、UPDATE
和DELETE
命令也执行锁定。
默认情况下,它们在当前事务期间锁定在记录级别;
如果其中一个命令锁定了足够多的记录(默认设置为1000
),那么锁将自动提升为表锁。
LOCK
命令允许显式地设置表级锁,使能够更好地控制数据资源的锁。
INSERT
、UPDATE
或DELETE
可以通过指定%NOLOCK
关键字来覆盖LOCK
。
带有LOCK_TIMEOUT
选项的SQL SET OPTION
设置当前进程的INSERT
、UPDATE
、DELETE
或SELECT
操作的超时时间。
SQL支持$SYSTEM.SQL.Util.SetOption()
方法的CachedQueryLockTimeout
选项。
示例
下面的嵌入式SQL示例创建一个表,然后锁定它:
ClassMethod Lock()
{
n SQLCODE,%msg
&sql(
CREATE TABLE mytest (
ID NUMBER(12,0) NOT NULL,
CREATE_DATE DATE DEFAULT CURRENT_TIMESTAMP(2),
WORK_START DATE DEFAULT SYSDATE
)
)
if SQLCODE = 0 {
w !,"表创建"
} elseif SQLCODE = -201 {
w !,"表已经存在"
} else {
w !,"SQL表创建错误代码: ",SQLCODE
q
}
}
ClassMethod Lock1()
{
n SQLCODE,%msg
s x = $zh
&sql(
LOCK mytest IN EXCLUSIVE MODE WAIT 4
)
if SQLCODE = 0 {
w !,"表锁"
} elseif SQLCODE = -110 {
w "等待 ",$ZHOROLOG - x," 秒"
w !,"表被另一个进程锁定",!,%msg
} else {
w !,"错误: ",SQLCODE,!,%msg
}
}
从管理门户运行的SQL程序生成一个进程,该进程在程序执行时立即终止。
因此,锁几乎立即被释放。
因此,要观察锁冲突,首先在运行相同名称空间中的SQL Shell的终端中发出lock mytest IN EXCLUSIVE MOD
E命令。
然后运行上面的嵌入式SQL锁定程序。
在排他模式下从终端SQL Shell发出一个UNLOCK mytest
。
然后重新运行上面的嵌入式SQL锁定程序。