TX锁(Transaction Lock)分析

2024-04-07 08:18
文章标签 分析 lock transaction tx

本文主要是介绍TX锁(Transaction Lock)分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

TX锁(Transaction Lock)分析

作者: fuyuncat

来源: www.HelloDBA.com

前两天看到现场alert日志中有一些00060(Deadlock)的告警。查了一下日志文件,发现一些奇怪的现象,比如有些锁在Insert时产生的,有些死锁是对同一个对象产生的。于是在解决这些问题的同时,仔细研究了一下TX锁,总结了产生TX锁的各种情况。

数据记录被锁

    我们知道,Oracle中事务产生的索都是行级锁。也就说,事务在对表做更新操作(UpdateDelete)时,只在针对数据块中需要更新的数据记录加锁。这种类型的锁就是我们最常见的锁。看下面的例子:

SQL> create table t_lock(a number, b varchar2(20), c char(10)) initrans 1 maxtrans 3;
 
Table created
 
SQL> insert into t_lock values(1,1,1);
 
1 row inserted
 
SQL> commit;
 
Commit complete
 

会话1:

SQL> update t_lock set b='2' where a=1;
 
1 row updated
 

会话2:

SQL> delete t_lock where a=1;
 

会话1锁住了a=1的记录,会话试图删除该记录时,被hung住。

SQL> select * from dba_waiters;
 
WAITING_SESSION HOLDING_SESSION LOCK_TYPE MODE_HELD MODE_REQUESTED LOCK_ID1 LOCK_ID2
--------------- --------------- --------- --------- -------------- -------- --------
28            20              Transaction Exclusive Exclusive    1048671  40361
    

    并且,如果将t_lock的数据块dump出来的话,也可以看到在记录行上的锁标志

tl: 19 fb: --H-FL-- lb: 0x1  cc: 3

    其中,0x1对应的是产生锁的事务在数据块itl列表中的条目号。

数据块中itl条目达到最大限制时产生的锁

 

    ITL(Interested Transaction List)直白点说就是对该数据块“有兴趣”的事务列。也就是会对该数据块进行修改的事务。一个表的数据块上同时最多可以有多少个事务对其进行更新,是由创建表时的参数maxtrans指定的。但是,如果表建立在基于9i新特性ASSM(自动段空间管理)的表空间上的话,那么指定的maxtrans就无效,一律都是255。比如上面的例子中,我们指定了maxtrans3(表空间不是ASSM),所以同时最多只能有3个事务对一个数据块进行更新。看下面的例子。

    先给上面的表多插入一些数据:

SQL> insert into t_lock values(2,2,2);
 
1 row inserted
 
SQL> insert into t_lock values(3,3,3);
 
1 row inserted
 
SQL> insert into t_lock values(4,4,4);
 
1 row inserted
 
SQL> insert into t_lock values(5,5,5);
 
1 row inserted
 
SQL> commit;
 
Commit complete
    

会话1:

SQL> update t_lock set b='2' where a=1;
 
1 row updated
    

会话2:

SQL> update t_lock set b='2' where a=2;
 
1 row updated
    

会话3:

SQL> update t_lock set b='2' where a=3;
 
1 row updated
    

会话4:

SQL> update t_lock set b='2' where a=4;
 
1 row updated
    

前面已经占用了3itl slot,第4个事务再申请itl时被hung住了。

SQL> select * from dba_waiters;
 
WAITING_SESSION HOLDING_SESSION LOCK_TYPE MODE_HELD MODE_REQUESTED LOCK_ID1 LOCK_ID2
--------------- --------------- --------- --------- -------------- -------- --------
19            27              Transaction Exclusive Exclusive    1048671  40361
 

    Dump出数据块,可以看到itl已经达到最大限制条目数:

seg/obj: 0x87c0  csc: 0x00.a337dee9  itc: 3  flg: -  typ: 1 - DATA
     fsl: 0  fnx: 0x0 ver: 0x01
 
Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0008.053.00009ef3  0x00802e6a.71b4.2b  ----    1  fsc 0x0000.00000000
0x02   0x000d.037.0000a98a  0x0080655a.ac1f.2b  ----    1  fsc 0x0000.00000000
0x03   0x000c.004.0000acb9  0x008006a6.06bc.28  ----    1  fsc 0x0000.00000000
 

    这里我们需要提出另外一个问题,如果事务操作不是updatedelete,而是进行Insert操作,会不会也会达到maxtrans的限制呢?做个试验看下吧:

会话1:

SQL> update t_lock set b='2' where a=1;
 
1 row updated
    

会话2:

SQL> update t_lock set b='2' where a=2;
 
1 row updated
    

会话3:

SQL> update t_lock set b='2' where a=3;
 
1 row updated
 

会话4:

SQL> insert into t_lock values(6,6,6);
 
1 row inserted
    

这时,尽管已经分配itl条目给三个事务,但是第四个事务在做insert插入操作时并没有被hung住。

看下数据块dump内容:

Object id on Block? Y
 seg/obj: 0x87c0  csc: 0x00.a337df1b  itc: 3  flg: O  typ: 1 - DATA
     fsl: 0  fnx: 0xa03000c ver: 0x01
 
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0003.00b.0000a3ab  0x0080397c.0b0f.2a  ----    1  fsc 0x0000.00000000
0x02   0x0000.000.00000000  0x00806a5a.as1e.2b  ----    1  fsc 0x0000.00000000
0x03   0x000e.037.0000a458  0x14401ff2.17d8.2b  ----    1  fsc 0x0000.00000000
 

我们发现,确实只有三个transaction在这个数据块上。那么还有一个事务呢?别急,把下一个数据块dump出来看看:

Object id on Block? Y
 seg/obj: 0x87c0  csc: 0x00.a337df22  itc: 1  flg: O  typ: 1 - DATA
     fsl: 0  fnx: 0x0 ver: 0x01
 
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0004.038.0000a6dc  0x00806fbf.bb4e.0e  ----    1  fsc 0x0000.00000000
 

原来如此!在做insert操作时,如果发现数据块已经达到maxtrans的最大限制,就从freelist中取出下一空闲数据块进行插入操作,而不管是否达到pctused的限制了。

Table上有Index时达到maxtrans限制

以上的测试是针对table上没有index时做的测试。当在table上建了index,情况就变得复杂多了。

 

·        场景一:

SQL> drop table t_lock;
 
Table dropped
 
SQL> create table t_lock(a number, b varchar2(20), c char(10)) initrans 1 maxtrans 5;
 
Table created
 
SQL> insert into t_lock values(1,1,1);
 
1 row inserted
 
SQL> insert into t_lock values(2,2,2);
 
1 row inserted
 
SQL> insert into t_lock values(3,3,2);
 
1 row inserted
 
SQL> insert into t_lock values(4,4,2);
 
1 row inserted
 
SQL> insert into t_lock values(5,5,1);
 
1 row inserted
 
SQL> commit;
 
Commit complete
 
SQL> create index t_lock_idx on t_lock(a) maxtrans 3;
 
Index created
 

会话1:

SQL> delete from t_lock where a=1;
 
1 row deleted      
 

会话2:

SQL> delete from t_lock where a=2;
 
1 row deleted 

(注意:以上操作都会索引列)

 

会话3:

SQL> update t_lock2 set b=2 where b=2;
 
1 row updated

(注意:这个会话没有涉及索引列)

 

会话4

SQL> delete from t_lock where a=3;

 

4个会话被hung住了:

SQL> select * from dba_waiters;
 
WAITING_SESSION HOLDING_SESSION LOCK_TYPE MODE_HELD MODE_REQUESTED LOCK_ID1 LOCK_ID2
--------------- --------------- --------- --------- -------------- -------- --------
19            20              Transaction Exclusive Share         393284   42733

 

我们的table上的maxtrans5,这里并没有达到,而index上的maxtrans3,第4Transactionhung。这里似乎可以下一个结论:table上有index的话,如果达到index上的maxtrans限制,后面的事务就会被hung住。但是,请注意第3个会话,他的操作并没有涉及到索引列,那么去掉第3个会话会怎样?

 

·        场景二:

会话1:

SQL> delete from t_lock where a=1;
 
1 row deleted      

 

会话2:

SQL> delete from t_lock where a=2;
 
1 row deleted 

(注意:以上操作都会索引列)

 

会话3:

SQL> delete from t_lock where a=3;

 

第3个会话被hung住了:

SQL> select * from dba_waiters;
 
WAITING_SESSION HOLDING_SESSION LOCK_TYPE MODE_HELD MODE_REQUESTED LOCK_ID1 LOCK_ID2
--------------- --------------- --------- --------- -------------- -------- --------
27            20              Transaction Exclusive Share         1048605  40351

 

这里,第3个会话就被hung住了。那就是说对有index得情况来说,itl数的限制是minx(maxtrans_of_index1 - 1, maxtrans_of_index2 – 1..., maxtrans_of_table) 。

 

我们前面提到,如果在insert时发现数据块的itl数已经达到maxtrans的限制,那么会在一个新的数据块进行插入,以避免会话阻塞。那么有了index以后,是否还是这样呢?看下面这种情况。

 

·        场景三:

 

会话1:

SQL> delete from t_lock where a=1;
 
1 row deleted      

 

会话2:

SQL> delete from t_lock where a=2;
 
1 row deleted 

(注意:以上操作都会索引列)

 

会话3:

SQL> insert into t_lock values(6,6,6);

 

第3个会话被hung住了:

SQL> select * from dba_waiters;
 
WAITING_SESSION HOLDING_SESSION LOCK_TYPE MODE_HELD MODE_REQUESTED LOCK_ID1 LOCK_ID2
--------------- --------------- --------- --------- -------------- -------- --------
19            20              Transaction Exclusive Share        131099    40859

 

我们看到,尽管达到maxtrans限制的会话是一个insert操作,但它还是被阻塞了。并不是想没有index时那样重新分配一块block。我想,oracle这样做的目的是为了保持index块的紧凑把。否则,试想,如果index块像data 块一样分布,index scan的意义就不大了。

 

有index情况比较复杂,很难知道Oracle内部是怎么处理的。但是,尽管从逻辑上分析,被lock住的对象应该是index,但从v$locked_object视图中查到的却是table。莫非oracle在做加锁时,是把index看作是table的一部分,而不是独立的资源(事实上,将index dump出来的话,它的行锁机制应该和数据块上差不多,不同的是,在做update操作时,index块上是先delete,然后insert,而数据块上是直接update)?

Bitmap Index条目被锁

如果Index是bitmap index,那么还有一种情况能产生tx锁。

我们知道,bitmap index一般建立在distinct值数目比较少的字段上。Oracle会建立一个类似于二进制位图(所以叫bitmap index)的结构,位图上每个条目对应一个值。而每个值会对应多个rowid。类似以下:

0rowid_1, rowid_5, rowid_11, rowid_20 ...
1: rowid_2, rowid_3, rowid_7, rowid_13 ...
2: rowid_4, rowid_6, rowid_8, rowid_12 ...
...

 

而如果多个会话需要同时更新一个条目对应的不同记录中位图索引列的话,就会产生争用,导致之中的会话被阻塞。看以下例子:

SQL> create bitmap Index t_lock_bmidx on t_lock(c);
 
Index created
 

会话1:

SQL> update t_lock set c=0 where a=1;
 
1 row updated

 

会话2:

SQL> update t_lock set c=0 where a=5;

 

会话2被hung住。

SQL> select * from dba_waiters;
 
WAITING_SESSION HOLDING_SESSION LOCK_TYPE MODE_HELD MODE_REQUESTED LOCK_ID1 LOCK_ID2
--------------- --------------- --------- --------- -------------- -------- --------
27            20              Transaction Exclusive Share         196635    41890

 

请注意以上两个transaction更新的记录是a=1和a=5,它们对应的c值都是1,因此第2个会话被hung住。

 

唯一性约束条件导致的tx

唯一性约束很简单,就是要保证被约束的字段不会有多于1条的重复记录。所以,事务会加上相应的tx锁,以保证约束不被违反。而如果两个事务提交后的结果会导致约束冲突的话,那么后来的会话就会被阻塞。

 
SQL> alter table t_lock
  2    add constraint t_lock_pk primary key (a);
 
Table altered

 

会话1:

SQL> insert into t_lock values(6,6,6);
 
1 row inserted

 

会话2:

SQL> update t_lock set a=6 where a=1;

 

可以看到,第2个会话被hung住了。

SQL> select * from dba_waiters;
 
WAITING_SESSION HOLDING_SESSION LOCK_TYPE MODE_HELD MODE_REQUESTED LOCK_ID1 LOCK_ID2
--------------- --------------- --------- --------- -------------- -------- --------
27            28              Transaction Exclusive Share         196683   41866

 

其它

事实上,产生tx锁还有一些其它情况。以上我所分析的都是常见的情况以及我所遇到的情况。

Tx锁是为了控制并发进程以及数据完整性而产生的。系统中产生tx锁应该是很常见的事(如果你去生产系统中查询v$lock视图,就能看到不少tx锁)。关键的问题是我们如何保证小事务不被大事务的tx锁阻塞,以及怎样避免死锁。希望以上的分析能够帮助你定位和解决这些问题。

 

这篇关于TX锁(Transaction Lock)分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/882092

相关文章

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

Spring、Spring Boot、Spring Cloud 的区别与联系分析

《Spring、SpringBoot、SpringCloud的区别与联系分析》Spring、SpringBoot和SpringCloud是Java开发中常用的框架,分别针对企业级应用开发、快速开... 目录1. Spring 框架2. Spring Boot3. Spring Cloud总结1. Sprin