掘金 后端 ( ) • 2024-03-27 14:35

1、概念

DM 数据库支持多用户并发访问、修改数据,有可能出现多个事务同时访问、修改相同 数据的情况。若对并发操作不加控制,就可能会访问到不正确的数据,破坏数据的一致性和 正确性。 封锁机制是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据库对象进 行操作前,需要先对其封锁。封锁后事务就对该数据库对象有了一定的控制,在该事务释放 锁之前,其他的事务不能对此数据库对象进行相应操作。

2、锁模式

锁模式指定并发用户如何访问锁定资源。DM 数据库使用四种不同的锁模式:共享锁、 排他锁、意向共享锁和意向排他锁。

  1. 共享锁

共享锁(Share Lock,简称 S 锁)用于读操作,防止其他事务修改正在访问的对象。 这种封锁模式允许多个事务同时并发读取相同的资源,但是不允许任何事务修改这个资源。

  1. 排他锁

排他锁(Exclusive Lock,简称 X 锁)用于写操作,以独占的方式访问对象,不允 许任何其他事务访问被封锁对象;防止多个事务同时修改相同的数据,避免引发数据错误; 防止访问一个正在被修改的对象,避免引发数据不一致。一般在修改对象定义时使用。

  1. 意向锁

意向锁(Intent Lock)用于读取或修改被访问对象数据时使用,多个事务可以同时 对相同对象上意向锁,DM 支持两种意向锁:

  1. 意向共享锁(Intent Share Lock,简称 IS 锁):一般在只读访问对象时使用;
  2. 意向排他锁(Intent Exclusive Lock,简称 IX 锁):一般在修改对象数据 时使用。

四种锁模式的相容矩阵如下表所示,其中―Y‖表示相容;―N‖表示不相容。如表中第二 行第二列为―Y‖,表示如果某个事务已经加了 IS 锁时,其他事务还可以继续添加 IS 锁, 第二行第五列为―N‖,表示如果某个事务已经加了 IS 锁时,其他事务不能添加 X 锁。

image.png

3、锁粒度

按照封锁对象的不同,锁可以分为 TID 锁和对象锁。

  1. TID 锁

TID 锁以事务号为封锁对象,为每个活动事务生成一把 TID 锁,代替了其他数据库行 锁的功能,防止多个事务同时修改同一行记录。DM 实现的是行级多版本,每一行记录隐含 一个 TID 字段,用于事务可见性判断。 执行 INSERT、DELETE、UPDATE 操作时,设置事务号到 TID 字段。这相当于隐式地 对记录上了一把 TID 锁,INSERT、DELETE、UPDATE 操作不再需要额外的行锁,避免了 大量行锁对系统资源的消耗。只有多个事务同时修改同一行记录时,才会产生新的 TID 锁。 例如,当事务 T1(事务号为 TID1)试图修改某行数据,而该行数据正在被另一个事务 T2 (事务号为 TID2)修改,此时事务 T1 会生成一个新的 TID 锁,其锁对象为事务号 TID2, 而非事务 T2。 同时多版本写不阻塞读的特性,SELECT 操作已经消除了行锁,因此 DM 中不再有行锁 的概念。

  1. 对象锁

对象锁是 DM 新引入的一种锁,通过统一的对象 ID 进行封锁,将对数据字典的封锁和 表锁合并为对象锁,以达到减少封锁冲突、提升系统并发性能的目的。我们先看一下通常数 据字典锁和表锁各自应承担的功能:

  1. 数据字典锁:用来保护数据字典对象的并发访问,解决 DDL 并发和 DDL/DML 并发 问题,防止多个事务同时修改同一个对象的字典定义,确保对同一个对象的 DDL 操作是串行执行的。并防止一个事务在修改字典定义的同时,另外一个事务修改对 应表的数据。

  2. 表锁:表锁用来保护表数据的完整性,防止多个事务同时采用批量方式插入、更新 一张表,防止向正在使用 FAST LOADER 工具装载数据的表中插入数据等,保证 这些优化后数据操作的正确性。此外,表锁还有一个作用,避免对存在未提交修改 的表执行 ALTER TABLE、TRUNCATE TABLE 操作。 为了实现与数据字典锁和表锁相同的封锁效果,从逻辑上将对象锁的封锁动作分为四

类:

a) 独占访问(EXCLUSIVE ACCESS),不允许其他事务修改对象,不允许其他 事务访问对象,使用 X 方式封锁

b) 独占修改(EXCLUSIVE MODIFY),不允许其他事务修改对象,允许其他事 务共享访问对象,使用 S + IX 方式封锁

c) 共享修改(SHARE MODIFY),允许其他事务共享修改对象,允许其他事务 共享访问对象,使用 IX 方式封锁

d) 共享访问(SHARE ACCESS),允许其他事务共享修改对象,允许其他事务 共享访问对象,使用 IS 方式封锁

  1. 显式锁定表

用户可以根据自己的需要显式的对表对象进行封锁。显式锁定表的语法如下: LOCK TABLE <table_name> IN <lock_mode> MODE [NOWAIT];

lock_mode 是锁定的模式,可以选择的模式有 INTENT SHARE(意向共享)、INTENT EXCLUSIVE(意向排他)、SHARE(共享)和 EXCLUSIVE(排他),其含义分别如下:

  1. 意向共享:不允许其他事务独占修改该表。意向共享锁定后,不同事务可以同时增、 删、改、查该表的数据,也支持在该表上创建索引,但不支持修改该表的定义;

  2. 意向排他:不允许其他事务独占访问和独占修改该表。被意向排他后,不同事务可 以同时增、删、改、查该表的数据,不支持在该表上创建索引,也不支持修改该表

定义;

  1. 共享:只允许其他事务共享访问该表,仅允许其他事务查询表中的数据,但不允许 增、删、改该表的数据;

  2. 排他:以独占访问方式锁定整个表,不允许其他事务访问该表,是封锁力度最大的 一种封锁方式。

当使用 NOWAIT 时,若不能立即上锁成功则立刻返回报错信息,不再等待。

4、查看锁

为了方便用户查看当前系统中锁的状态,DM 数据库专门提供了一个 V$LOCK 动态视图。 通过该视图,用户可以查看到系统当前所有锁的详细信息,如锁的内存地址、所属事务 ID、 锁类型、锁模式等。用户可以通过执行如下语句查看锁信息:

SELECT * FROM V$LOCK;

其结果看起来和下面类似:

image.png

其中 ADDR 列表示锁的内存地址;TRX_ID 列表示锁所属的事务 ID;LTYPE 列表示锁 的类型,可能是 OBJECT(对象锁)或者 TID(TID 锁);LMODE 表示锁的模式,可能的 取值有 S(共享锁)、X(排他锁)、IS(意向共享锁)、IX(意向排他锁);BLOCKED 列表示锁是否处于上锁等待状态,0 表示已上锁成功,1 表示处于上锁等待状态;TABLE_ID 列对于对象锁,表示表对象或字典对象的 ID,对于 TID 锁,表示封锁记录对应的表 ID; ROW_IDX 列为 TID 锁封锁记录的行信息;TID 列为 TID 锁对象事务 ID。

5、实操

1、锁定表

LOCK TABLE cases.CASES_DETAIL  IN EXCLUSIVE  MODE ;

2、找到锁定表

1、找到等待会话的事务id

-- 查询正在等待的会话,来获取事务 trx_id 
select * from  v$sessions where State = 'WAIT';

image.png

2、获取事务等待的锁id

-- 根据事务id,来获取  WAITING  事务等待的锁 的id
select * from v$trx where id = 14764429;

image.png

3、根据锁对象id 来获取 table_id

-- 根据 锁对象的id ,table_id 
select * from v$lock  where addr = '140196514260368' ;

image.png

4、根据table_id 来获取被锁的对象表

-- 根据table_id 来获取被锁的对象表
select * from sys.ALL_OBJECTS where object_Id = 1371

image.png

可以看到已经找到了该 表。

5、释放该锁

1、根据表名或者,对于的对象id

SELECT OBJECT_ID FROM ALL_OBJECTS WHERE OBJECT_NAME='CASES_DETAIL';

2、根据table_id 来获取锁对应信息的会话。

select * from v$lock where table_id = 1371

image.png

对应为 X 为排他锁。

3、根据事务id,找到会话id

select * from  v$sessions where trx_id = '14764427'

image.png

4、关闭当前会话。锁释放

SP_CLOSE_SESSION(140194254225616);

3、批量关闭会话

begin
for row_data in (select sess_id from v$sessions where APPNAME = 'SQLark Client') loop
    sp_close_session(row_data.sess_id);
    dbms_output.put_line(row_data.sess_id);
end loop;

end