如果我从应用程序中的多个线程调用以下代码,是否存在死锁风险?用于连接数据库的事务在此调用之前打开,一旦返回就关闭。 应用程序:Java 数据库:Oracle
FUNCTION reserveWork(in_batch_id NUMBER,
in_work_size NUMBER,
in_contentType_id NUMBER) RETURN NUMBER IS
rows_reserved NUMBER := 0;
BEGIN
UPDATE
D_Q1
SET
DQ1_BAT_ID = in_batch_id
WHERE
DQ1_BAT_ID is null
AND DCT_ID = in_contentType_id
AND ROWNUM < (in_work_size + 1);
rows_reserved := SQL%ROWCOUNT;
RETURN (rows_reserved);
END;
答案 0 :(得分:2)
为了发生死锁,你必须具备这两个条件。
每个事务必须有多个锁。
必须以不同的顺序抓住锁。
条件1为true,因为每个线程都锁定多行。 条件2在理论上是正确的,因为返回的行的顺序不是确定性的。例如,线程1可能会尝试更新行1,2,3,而线程2可能会尝试更新行3,2,1。
实际上,Oracle可能总是以相同的顺序返回行,因此它可能永远不会死锁。无论如何,准备好处理ORA-00060错误并重新提交请求。
另一个想法是分两步完成。第一个过程执行SELECT * WHERE ... FOR UPDATE NO WAIT来锁定行,如果没有返回ORA-00054,则第二个过程执行实际更新。否则你重试。
无论哪种方式,请确保您的CREATE TABLE中的INITTRANS设置为同时更新表的客户端数。
答案 1 :(得分:1)
如果您在同一个表上运行多个UPDATE,则存在明确的死锁风险。
特别是因为我在代码中看不到COMMIT或ROLLBACK?我认为这是在JDBC中完成的?
UPDATE越长,死锁风险就越高。
答案 2 :(得分:1)
当事务A锁定记录然后必须等待事务B解锁记录时发生死锁,而事务B正在等待事务A已经锁定的记录。
Oracle在更新过程中有一种非常复杂的机制来处理对表的更改。参见
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:11504247549852
通常,死锁的风险会增加事务运行的时间越长,事务更改的数据就越多。我说这不太可能死锁,但可能会“排队” - 如果你有三个或四个并发会话运行这个SQL,每个会话将具有相同的SQL执行路径,将识别相同的行进行更新,一个人会先找到他们,其他人会等。当第一个事务完成时,另一个事务将重新获取记录,发现它们已被更改,并按照Tom Kyte的文章中的描述重新启动并选择下一行。
如果您使用的是11g,则可以使用SKIP LOCKED。它存在,但在早期版本中没有记录。因此,您将自行承担使用风险。
http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_10002.htm#SQLRF01702
这样,你就
了SELECT primary_key BULK COLLECT INTO pk_variable_array FROM D_Q1
WHERE DQ1_BAT_ID is null
AND DCT_ID = in_contentType_id
AND ROWNUM < (in_work_size + 1)
FOR UPDATE SKIP LOCKED;
--
FORALL i in 1..pk_variable_array
UPDATE D_Q1
SET DQ1_BAT_ID = in_batch_id
WHERE primary_key = pk_variable_array(i)