金仓数据库KingbaseES的锁机制

本文深入探讨金仓数据库KingbaseES的咨询锁机制,包括会话级和事务级咨询锁的特性与使用,以及排他与共享锁的交互。通过实例展示如何获取和释放锁,强调了在并发控制中的重要性。
摘要由CSDN通过智能技术生成

前言
在并发控制的过程中,事务隔离起着重要作用。事务隔离是控制如何和何时进行更改以及何时必须对彼此、用户和系统可见的属性。
金仓数据库KingbaseES通过多版本并发控制架构实现隔离。多版本并发控制是一种允许多个会话同时访问同一记录的技术,即,当会话 A 正在更新一条记录时,会话 B 仍然可以访问该记录。
但是以下情况,应该怎么办:

  1. 如果会话 A 和会话 B 都想同时更新相同的记录。
  2. 如果在会话 A 访问表时,在会话 B 中试图 truncate 表。
  3. 如果会话 A 正在更新表,而会话 B 试图 vacuum 表。
    这里出现了锁定的概念。
  4. 锁机制
    锁机制在 KingbaseES 里非常重要 (对于其他的 RDBMS 也是如此),特别是对于数据库应用开发人员,高并发应用的开发人员必须熟悉。大部分数据异常情况,跟死锁或者数据不一致有关系,基本上都是由于对锁机制不太了解导致的。
    锁定类型取决于执行的命令类型。 KingabseES 支持三种锁定机制:
  5. 表级锁 ( Table-Level Locks )
  6. 行级锁 ( Row-Level Locks )
  7. 咨询锁 ( Advisory Locks )
    表级和行级的锁可以是显式的也可以是隐式的,咨询性锁一般是显式的。显式的锁由显式的用户请求(通过特殊的查询)获取,隐式的锁是通过标准的 SQL 命令来获取。
    • 隐式锁意味着当事务结束时锁会默认关闭。
    • 显式锁一旦获得,可能会一直保持到显式释放。我们可以使用该WITH LOCK 语句显式获取锁。
    除了表级和行级的锁,还有页级共享/排除锁,用于控制对共享缓存池里表页的访问。在一行数据被读取或者更新后,这些锁会立即被释放。应用程序开发者通常不需要关注页级的锁。
  8. 表级锁 ( Table-Level Locks )
    表级锁通过内置 SQL 命令获取(隐式);此外,它们可以通过 LOCK 命令显式获取。表级锁包括:
    • 访问共享(ACCESS SHARE) - SELECT 命令可在查询中引用的表上获得该锁。一般规则是所有的查询中只有读表才获取此锁。
    • 行共享(ROW SHARE) - SELECT FOR UPDATE 和 SELECT FOR SHARE 命令可在目标表上获得该锁(以及查询中所有引用的表的访问共享锁)。
    • 行独占(ROW EXCLUSIVE) - UPDATE、INSERT 和 DELETE 命令在目标表上获得该锁(以及查询中所有引用的表的访问共享锁)。 一般规则是所有修改表的查询获得该锁。
    • 共享更新独占(SHARE UPDATE EXCLUSIVE) - VACUUM(不含FULL),ANALYZE,CREATE INDEX CONCURRENTLY,和一些 ALTER TABLE 的命令获得该锁。
    • 共享(SHARE) - CREATE INDEX(无 CONCURRENTLY) 命令在查询中引用的表上获得该锁。
    • 共享行独占(SHARE ROW EXCLUSIVE) - CREATE COLLATION, CREATE TRIGGER和多种形式 ALTER TABLE,获取此锁。
    • 独占(EXCLUSIVE) - REFRESH MATERIALIZED VIEW CONCURRENTLY,获取此锁。
    • 访问独占(ACCESS EXCLUSIVE) - ALTER TABLE,DROP TABLE,TRUNCATE,REINDEX,CLUSTER 和 VACUUM FULL 命令在查询中引用的表上获得该锁。此锁模式是 LOCK 命令的默认模式。
    最基本的是 Share 和 Exclusive 这两种锁,它们分别是读、写锁的意思。Share,即读锁,表的内容就不被修改了;可以为多个事务加上此锁,只要任意一个事务不释放这个读锁,则其他事务就不能修改这个表。Exclusive,相当于加了写锁,这时别的进程不能写也不能读这条数据。
    但后来数据库又加上了多版本的功能,修改一条语句的同时,允许了读数据。为了处理这种情况,又增加了两种锁Access Share和Access Excusive,锁中的关键字 Access 是与多版本相关的有了该功能。其实,有了该功能后,如果修改一行数据,实际并没有改原先那行数据,而是复制了一个新行,修改都在新行上,事务不提交,其他人是看不到修改的这条数据的。由于旧行数据没有变化,在修改过程中,读数据的人仍然可以读到旧的数据。
    表级锁加锁对象是表,这使得加锁范围太大,导致并发并不高,于是人们提出了行级锁的概念,但行级锁与表级锁之间会产生冲突,这时需要一种机制来描述行级锁与表级锁之间的关系,有了意向锁的概念,这时又加了两种锁,即意向共享锁(Row Share) 和意向排他锁(Row Exclusive),由于意向锁之间不会产生冲突,因为他们是“有意”做,还没真做;而且意向排它锁相互之间也不会产生冲突,于是又需要更严格一些的锁,这样就产生了 Share Update Exclusive , Share Row Exclusive 可以看成 Share 与 Row Exclusive 。
    2.1. 访问共享(ACCESS SHARE)
    访问共享锁是由只从表中读取但不修改它的查询获取的。通常,这是一个选择查询。
    隐式锁定示例:
  9. 从会话 1 中选择获取访问共享锁定的内容
    (SESSION 1)# begin ;
    BEGIN
    (SESSION 1)# select *, pg_sleep(300) from acl ;
  10. 尝试从会话 2 中截断表
    (SESSION 2)# begin;
    BEGIN
    (SESSION 2)# truncate table acl;

    会话 1 获取 AccessShareLock ,以获取记录。
    会话 2 想要 truncate 表,必须使用 AccessExclusiveLock 模式锁,但由于锁冲突,正在等待获取。
    ACCESS SHARE LOCK与ACCESS EXCLUSIVE锁定模式冲突。
    这时查看锁的信息,可以得到了两个锁。看到 AccessShareLock 的 granted 值是 true ,而 AccessExclusiveLock 的 granted 值是 false。
    kingbase=# ! ksql -c "select pid, virtualxid vxid, locktype lock_type, mode lock_mode, granted, relation::regclass relname from pg_locks WHERE relation = ‘acl’::regclass; "
    pid | vxid | lock_type | lock_mode | granted | relname
    ------±-----±----------±--------------------±--------±--------
    7244 | 6/9 | relation | AccessShareLock | t | acl
    7364 | 3/12 | relation | AccessExclusiveLock | f | acl
    (2 rows)
    查找锁和锁的PID
    kingbase=# ! ksql -c “SELECT locked.pid AS locked_pid, locker.pid AS locker_pid, locked_act.usename AS locked_user, locker_act.usename AS locker_user, locked.transactionid, relname FROM pg_locks locked LEFT OUTER JOIN pg_class ON (locked.relation = pg_class.oid), pg_locks locker, pg_stat_activity locked_act, pg_stat_activity locker_act WHERE locker.granted = true AND locked.granted = false AND locked.pid = locked_act.pid AND locker.pid = locker_act.pid AND locked.relation = locker.relation;”
    locked_pid | locker_pid | locked_user | locker_user | virtualtransaction | relname
    ------------±-----------±------------±------------±-------------------±--------------
    7364 | 7244 | kingbase | kingbase | 3/12 | acl
    (1 row)

显式锁定示例:
kingbase=# begin;
BEGIN
kingbase=# LOCK TABLE emp IN ACCESS SHARE MODE;
LOCK TABLE
kingbase=# ! ksql -c "select pid, virtualxid vxid, locktype lock_type, mode lock_mode, granted, relation::regclass relname from pg_locks WHERE relation = ‘emp’::regclass; "
pid | vxid | lock_type | lock_mode | granted | relname
------±-----±----------±----------------±--------±-----------------------------------
6020 | 4/8 | relation | AccessShareLock | t | emp
(1 rows)

kingbase=#

2.2. 行共享(ROW SHARE)
SELECT FOR UPDATE 和 SELECT FOR SHARE 命令在目标表上获取此模式的锁。
EXCLUSIVE 与 *ACCESS EXCLUSIVE *锁定模式冲突 。

  1. 从会话 1 中选择获取访问共享锁定的内容
    (SESSION 1)# begin ;
    BEGIN
    (SESSION 1)# select *, pg_sleep(300) from acl for update ;
  2. 从会话 2 查看锁和锁的PID信息
    kingbase=# ! ksql -c "select pid, virtualxid vxid, locktype lock_type, mode lock_mode, granted, relation::regclass relname from pg_locks WHERE relation = ‘acl’::regclass; "
    pid | vxid | lock_type | lock_mode | granted | relname
    ------±-----±----------±--------------------±--------±--------
    7691 | | relation | RowShareLock | t | acl
    (1 rows)

2.3. 行独占( ROW EXCLUSIVE )
命令 UPDATE、 DELETE和 INSERT在目标表上获取此锁定模式。
SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE等锁模式,与 ACCESS EXCLUSIVE 锁模式冲突 。
隐式锁定示例:
例子
(SESSION 1)#begin;
BEGIN
(SESSION 1)#select * from acl;
id | sno | name | sal | dept
----±----±-----±----±------
1 | 1 | A | 200 | IT
2 | 2 | B | 200 | IT
3 | 3 | C | 300 | SALES
(3 rows)

(SESSION 1)#insert into acl values(4,4,‘D’,400,‘IT’);
INSERT 0 1
(SESSION 1)#

现在,这个会话 1 获得了一个行独占锁。
从会话 2 开始,尝试更改表。
(SESSION 2)#alter table acl drop dept;

会话 2 将等待会话 1 释放锁,因为 alter t

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值