背景
在 Oceanbase 4.1 及之前的版本中,已经为 Oracle 租户提供了 LOCK TABLE 相关的语法,包括单表锁定操作,以及 WAIT N
和 NOWAIT
关键字。然而,使用上存在诸多限制,比如:LOCK TABLE 只能锁定单表,不支持多表锁定、分区锁定;WAIT N
和 NOWAIT
关键字并未实际生效,即在语句中指定WAIT N
或NOWAIT
后,实际的执行行为仍与未设置关键字一致,仍然使用设置的语句超时时间和事务超时时间的最小值来等待锁,也就是等待锁直到语句超时或事务超时。
想要了解相关语法和描述可以参考官方文档。LOCK TABLE
在 Oceanbase 4.2 及之后的版本中,提供了更完备的 LOCK TABLE 语法兼容性,并补全了未生效的功能,包括对多表、多分区、多二级分区上锁,以及使WAIT N
和NOWAIT
关键字生效。
LOCK TABLE 语法解析
LOCK TABLE 的语法如下所示:
LOCK TABLE
{
[ schema. ] table
[ PARTITION '('partition ...')'
| SUBPARTITION '(' subpartition ...')' ]
...
}
IN lockmode MODE
[ NOWAIT | WAIT integer] ;
其对应的语法结构图如下。
lock_table::=对应的语法结构见下图:
partition_extension_clause::=对应的语法结构见下图:
如果你对上述语法结构中的字段存疑,可以参考下表中对于LOCK TABLE 各字段的说明。
字段名称 | 描述 |
table | 指定要锁定的表的名称。 |
partition | 指定要锁定的分区的名称。 |
subpartition | 指定要锁定的二级分区的名称。 |
lockmode | 指定锁定模式。OceanBase 数据库当前版本支持的锁定模式如下。ROW SHARE:允许并发访问锁定的表,但禁止用户锁定整个表而进行独占访问。ROW EXCLUSIVE :与 ROW SHARE 相同,但也禁止在 SHARE 模式下锁定表。在进行更新、插入或删除时,将自动获得 ROW EXCLUSIVE 锁。SHARE:允许并发查询,但禁止更新锁定的表。SHARE ROW EXCLUSIVE:用于查看整个表,并允许其他人查看表中的行,但禁止其他人在 SHARE 模式下锁定表或更新行。EXCLUSIVE:只允许对锁定的表进行查询,禁止对其进行其他操作。 |
NOWAIT | 如果对执行的表、分区或二级分区上锁时发生锁冲突,则指定 NOWAIT 可以让数据库立即将控制权返回给用户。在这种情况下,数据库会返回一条消息,以告知表、分区或子分区已被另一个用户锁定。 |
WAIT | 如果发生锁冲突,那么语句应该等待冲突的锁释放,直到超过用户设置的 interger 时间(单位对应为秒),integer 的值没有限制。 |
LOCK TABLE 语法实践
了解基本概念和原理后,我们来上手实践一下。以如下所示的表结构作为实践操作表,演示10个操作场景。其中,subpartition template 生成的二级分区名称为一级分区名称 + 's' + 二级分区模板名称
,例如,p0
分区有二级分区p0ssp0
、p0ssp1
和p0ssp2
。
create table test(col1 int, col2 int)
partition by range (col1)
subpartition by range (col2)
subpartition template
(
subpartition sp0 values less than (3),
subpartition sp1 values less than (6),
subpartition sp2 values less than (9)
)
(
partition p0 values less than (100),
partition p1 values less than (200),
partition p2 values less than (300)
);
场景1:对整个表上互斥锁。
lock table test in exclusive mode;
场景2:对一级分区p1
上互斥锁。
lock table test partition (p1) in exclusive mode;
场景3:对二级分区p1ssp1
上互斥锁。
lock table test subpartition (p1ssp1) in exclusive mode;
场景4:在两个客户端上分别对同一个表上锁,其中持锁客户端上互斥锁,请求锁客户端上共享锁。
# conn1
start transaction;
lock table test in exclusive mode;
# conn2
start transaction;
set ob_trx_timeout = 10000000000; # 10000 second
set ob_query_timeout = 1000000; # 1 second
# client will get error code after 1 second
lock table test in share mode;
ERROR HY000: resource busy and acquire with NOWAIT specified or timeout expired
当 LOCK TABLE 语句不设置WAIT N
/NOWAIT
关键字时,其超时时间将取决于语句超时时间和事务超时时间的最小值,在该例子中即为 1 秒后将报出锁冲突错误。
场景5:在两个客户端上分别对同一个表上表锁,其中持锁客户端上互斥锁,请求锁客户端上共享锁,并使用NOWAIT
关键字。
# conn1
start transaction;
lock table test in exclusive mode;
# conn2
start transaction;
lock table test in share mode nowait;
ERROR HY000: resource busy and acquire with NOWAIT specified or timeout expired
当 LOCK TABLE 语句设置了NOWAIT
关键字后,若遇到表锁冲突将会立即报错,并在报错信息中体现“NOWAIT”信息。该报错信息与语句不设置WAIT N
/NOWAIT
关键字不同。
场景6:在两个客户端上分别对同一个表上表锁,其中持锁客户端上互斥锁,请求锁客户端上共享锁,并使用WAIT N
关键字。
# conn1
start transaction;
lock table test in exclusive mode;
# conn2
start transaction;
# client will get error code after 1 second
lock table test in share mode wait 1;
ERROR HY000: resource busy and acquire with NOWAIT specified or timeout expired
当 LOCK TABLE 语句设置了WAIT N
关键字后,若遇到表锁冲突将会等待N
秒,若N
秒后为解锁将报错,并在报错信息中体现“timeout expired”信息。该报错信息与语句不设置WAIT N
/NOWAIT
关键字不同。
场景7:对一个表的多个分区上互斥锁。
lock table test partition (p1,p2) in exclusive mode;
场景8:对一个表的多个二级分区上互斥锁。
lock table test subpartition (p0ssp1,p1ssp2) in exclusive mode;
场景9:对一个表的多个分区和二级分区上互斥锁。
lock table test partition (p1, p2), test subpartition (p3ssp0, p3ssp1) in exclusive mode;
场景10:对不存在的分区上互斥锁(其中p3
分区不存在,但是p0
分区也不会上锁成功,整条语句将回滚).
lock table test partition (p0, p3) in exclusive mode;
ERROR HY000: Specified partition does not exist
写在最后
LOCK TABLE 语句是生产场景中常用的并发控制手段,可以帮助用户简单高效地实现表级的 ddl / dml 互斥。本文介绍了 OceanBase v4.2 新增的 LOCK TABLE Oracle 语法兼容的新特性,从语法的结构、字段的描述等角度详细解析了该新特性的使用方法,并分享了新特性的场景实践,希望能够帮助大家更“丝滑”地使用该特性,也欢迎大家在评论区分享优化建议、使用体验等。