当在表中更新和删除不同的行时,是否可能发生死锁?

9
在Oracle 10+版本中,即使它们同时在同一表的不同行上操作,更新和删除同一张表是否会导致死锁?
该表具有由两列组成的主键,并且没有任何与其他表相关/引用的外键。并且与其他表没有父/子关系。
我相信这不会创建死锁,但我的应用程序出现了问题。
添加Oracle跟踪:
以下死锁不是ORACLE错误。这是由于应用程序设计的用户错误或发出不正确的即席SQL而导致的死锁。以下信息可能有助于确定死锁:
Deadlock graph:
                       ---------Blocker(s)--------  ---------Waiter(s)---------
Resource Name          process session holds waits  process session holds waits
TX-0007003e-0081d6c3        45     790     X            104      20           X
TX-00080043-0085e6be       104      20     X             45     790           X

session 790: DID 0001-002D-000035F9     session 20: DID 0001-0068-000007F6
session 20: DID 0001-0068-000007F6      session 790: DID 0001-002D-000035F9

Rows waited on:
  Session 790: obj - rowid = 0000F0C8 - AAAPDIAAMAAAEfIAAA
  (dictionary objn - 61640, file - 12, block - 18376, slot - 0)
  Session 20: obj - rowid = 0000F0C8 - AAAPDIAAMAAAEfGAAA
  (dictionary objn - 61640, file - 12, block - 18374, slot - 0)

----- Information for the OTHER waiting sessions ----- Session 20:
  sid: 20 ser: 4225 audsid: 57496371 user: 72/RPT_TABLE
    flags: (0x45) USR/- flags_idl: (0x1) BSY/-/-/-/-/-
    flags2: (0x40009) -/-/INC
  pid: 104 O/S info: user: oracle, term: UNKNOWN, ospid: 20798
    image: oracle@caidb10p-node1
  client details:
    O/S info: user: gtsgen, term: unknown, ospid: 1234
    machine: caiapp08p-node0.nam.nsroot.net program: JDBC Thin Client
    application name: JDBC Thin Client, hash value=2546894660
  current SQL:
  delete from RPT_TABLE.TEMP_TABLE_T1 where TEMP_T1_ID=:1

----- End of information for the OTHER waiting sessions -----

Information for THIS session:

----- Current SQL Statement for this session (sql_id=bsaxpc2bdps9q) ----- UPDATE RPT_TABLE.TEMP_TABLE_T1 temp1 SET temp1.CLIENT_ID = (SELECT MIN(INVMAP.CLIENT_ID) FROM LI_REF.REF_CLIENT_MAP INVMAP WHERE INVMAP.F_CODE = :B2 AND INVMAP.AID = temp1.ID AND temp1.R_ID=:B1 )
----- PL/SQL Stack -----
----- PL/SQL Call Stack -----
  object      line  object
  handle    number  name
45887d750        24  procedure RPT_TABLE.T1_UPDATE_StoredProc  

6399ba188         1  anonymous block

如果所有的事务确实在更新完全不同的行,那么死锁似乎是非常不可能的。如果你面临这种情况,那么我会怀疑是否有一些事务正在更新相同的行。 - user330315
你遇到了什么问题?这个描述太过笼统,只能给出非常模糊的答案,并告诉你去阅读文档。你认为引起问题的代码 - 无论是什么 - 也会有所帮助,同时还需要详细说明正在发生的情况,包括任何错误信息。 - Alex Poole
2个回答

10
如果您能使用死锁图更新您的问题,那将是有用的信息。(当您的应用程序遇到死锁时,Oracle会引发ORA-00060错误,并且将一个跟踪文件写入用户转储目录。)如果您查看跟踪文件,您会找到一个名为"Deadlock Graph"的部分。如果您可以发布它,以及引起死锁的语句和其他涉及死锁的语句,那么我们就可以开始得出一些结论。(我所请求的所有信息都在跟踪文件中。)
正如Alessandro所提到的,可能会因为父/子关系中子表的未索引外键而导致锁定同一表中不同行的会话死锁。此外,即使表不是父/子关系的一部分,如果表缺乏ITL条目,可能会发生两个会话更新相同表的不同行的死锁。
再次强调,请发布上述请求的信息,我相信我们可以确定死锁的根本原因。
**添加于2012年7月30日**
鉴于已经提供了死锁跟踪文件,现在添加以下内容: 好的,首先,根据跟踪文件内容,这是由于会话在它们尝试锁定的行上重叠/冲突而导致的简单死锁。尽管您先前的评论是关于死锁发生在不同的行上,但我在这里告诉您,这个特定的死锁是由于在相同的行上进行行级别锁定。
死锁图显示被持有的锁模式是“X”(独占),等待的锁模式也是“X”,告诉我这是简单的行级别锁定。
在这种情况下,SID 20正在执行“delete from RPT_TABLE.TEMP_TABLE_T1 where TEMP_T1_ID=:1”,并且已经锁定了rowid AAAPDIAAMAAAEfIAAA。
同时,SID 790正在执行“RPT_TABLE.T1_UPDATE_StoredProc”,同时已经持有rowid AAAPDIAAMAAAEfGAAA的锁。从跟踪文件的“等待行”部分可以看出,SID 20正在等待SID 790持有的行,而SID 790正在等待SID 20持有的行,这是一种经典的死锁情况。
其他一些信息:
- Enqueue类型为TX(请参见死锁图),因此这绝对不是由于未建立索引的外键而导致的锁定。如果是由于未建立索引的FK而进行锁定,则Enqueue类型将为TM而不是TX。(至少还有一种涉及TM enqueues的情况,它并不是未建立索引的FK。因此,请不要认为TM enqueue总是指未建立索引的FK。) - 等待锁定的模式是'X'(独占),因此这是行级锁定。如果等待的模式是'S'(共享),那么它就不是行级锁定。相反,它可能是ITL短缺或PK或UK执行。
希望这可以帮助!

感谢您详细的回复。 关于user_dump_dest位置,我能否从user_dump_dest获取一周前的跟踪文件。 - lowLatency
就父/子关系而言,这并不是FK的情况...但是,正如您所提到的...有两个会话更新同一表的不同行...请在此方面给我更多指导...ITL条目短缺...请求您进一步详细说明此事... - lowLatency
2
请不要试图猜测死锁的原因,请提供来自死锁跟踪文件的信息。关于您是否可以从一周前检索跟踪文件,这取决于您的user_dump_dest有多大,您清除它的频率是多少等等。我建议尝试在user_dump_dest目录中运行“grep -l“ORA-00060”*.trc”。 - Mark J. Bobak
同样也添加了跟踪。 - lowLatency

9

我不知道你的应用程序是否涉及外键,但这可能是锁定的原因。如果是的话,请查看以下链接:

http://docs.oracle.com/cd/E11882_01/server.112/e16508/consist.htm#BABCAHDJ

http://docs.oracle.com/cd/E11882_01/server.112/e16508/datainte.htm#CNCPT1657

Oracle数据库最大化了父键与从属外键的并发控制。锁定行为取决于外键列是否被索引。如果外键没有被索引,那么子表可能会更频繁地被锁定,死锁会发生,从而降低并发性。因此,几乎总是应该对外键进行索引。唯一的例外是匹配的唯一或主键永远不会被更新或删除。
锁定和未索引的外键
当以下两个条件都成立时,数据库会在子表上获取完整的表锁:
- 子表的外键列上不存在索引。 - 会话修改父表中的主键(例如,删除行或修改主键属性)或合并行到父表中。插入到父表中不会在子表上获取表锁。
如果这不是您的情况,请尝试提供更多信息。告诉我们会话持有/请求的锁的类型,并查看系统表V$LOCK、V$LOCKED_OBJECT、DBA_DDL_LOCKS、DBA_DML_LOCKS或V$SESSION_WAIT。

谢谢,这正是我的情况。更糟糕的是——父表甚至没有包含任何行。真的——从空表中删除在引用表上产生了TM锁。添加索引有所帮助。 - Blaf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接