这段时间应用一直被一个诡异的ORA-00060的错误所困扰,众所周知,造成ORA-00060的原因是由于应用逻辑,而非Oracle数据库自己,之所以说诡异(“诡异”可能不准确,只能说这种场景,以前碰见的少,并未刻意关注),是因为这次不是常见的,由于读取数据顺序有交叉,导致ORA-00060,关于读取数据顺序错误,导致ORA-00060的错误场景,可以参考《ORA-00060的示例与若干场景》(https://blog.csdn.net/bisal/article/details/14227997)。
再说我碰见的问题之前,引用一些JL大神《Oracle Core》,对于死锁的一些介绍,一些(易混淆/不清晰)概念,后面可能会用上,
Oracle用户群里一个众所周知的说法是“读不阻塞写,写不阻塞读”,但这仅限于数据级别;当深入到底层的原始内存级别时,有时候读者必须阻塞写者才行,并且单个写操作必须阻塞其他所有操作。
每个由事务修改的数据(或索引)块都会在他的事务列表中引用该事务表槽。执行事务的会话都会为事务表槽创建一个排队资源(类型为TX,id1表示undo段号和槽号,id2表示槽序列号)来锁定他,并将一个排队(enqueue)附加到这个资源上-具体来说,是x$ktcxb中的一行,而不是x$ksqeq-锁模式为6(独占锁)。
混淆:
1. 当然可能有多个会话陷入循环等待,死锁不仅仅限于两个会话之间,尽管最常见的是两个。
2. 尽管模式6类型的TX锁是死锁中最常见的,但任何时候只要等待一个锁,都有可能会出现ORA-00060场景。
死锁场景:
1. 两个会话试图插入相同的主键值。
2. 一个会话在另一个会话删除父行时插入一行到子表中。
3. 一个会话插入一条父行,然后另一个会话在父行提交前插入子行。
4. 两个会话试图删除由同一个位图索引块(chunk)所覆盖的行。
本质上讲,如果由于索引(或由这些索引关联的约束)争用,导致你必须等待其他会话提交,那么你会看到一个模式4的TX等待。甚至有一个不是由编码问题引起的索引情况-当你等待其他会话完成索引块分裂时。
如下是官方文档,对于TX锁的介绍,字面含义“行锁”(“行锁”是否正确?后面JL帖子回复,会纠正这个错误),
Row Locks (TX)
A row lock, also called a TX lock, is a lock on a single row of table. A transaction acquires a row lock for each row modified by an INSERT, UPDATE, DELETE, MERGE, or SELECT ... FOR UPDATE statement. The row lock exists until the transaction commits or rolls back.
Row locks primarily serve as a queuing mechanism to prevent two transactions from modifying the same row. The database always locks a modified row in exclusive mode so that other transactions cannot modify the row until the transaction holding the lock commits or rolls back. Row locking provides the finest grain locking possible and so provides the best possible concurrency and throughput.
If a transaction obtains a lock for a row, then the transaction also acquires a lock for the table containing the row. The table lock prevents conflicting DDL operations that would override data changes in a current transaction. Figure illustrates an update of the third row in a table. Oracle Database automatically places an exclusive lock on the updated row and a subexclusive lock on the table.
TM锁的介绍,
Table Locks (TM)
A table lock, also called a TM lock, is acquired by a transaction when a table is modified by an INSERT, UPDATE, DELETE, MERGE, SELECT with the FOR UPDATE clause, or LOCK TABLE statement. DML operations require table locks to reserve DML access to the table on behalf of a transaction and to prevent DDL operations that would conflict with the transaction.
这是锁类型介绍,不同的锁模式,代表了不同的锁粒度,
先说下我的问题背景,
1. 这是高并发的一个OLTP应用。
2. 应用采用了多线程处理逻辑。
问题现象:
1. 数据库层面出现大量“enq: TX - row lock contention”,行锁等待。
2. 应用进程会话,hang在DELETE删除一张父表的操作上,20+分钟。
3. 在这20分钟的期间,非常多的应用进程会话,执行INSERT子表记录的时候,提示ORA-00060错误,经过统计,总计共有160个会话,提示ORA-00060错误,换句话说,所有INSERT提示ORA-00060之后,(1)中的DELETE操作完成。
以下是参考应用日志,创建测试表、外键约束、唯一约束、以及索引,模拟还原了出错的过程,
表:
create table lock_a (id number primary key, name v