我们的应用程序从Oracle'事件中读取记录。表。当事件记录存在时,我们会更新'计数'该记录的领域。如果记录不存在,我们将其插入。因此,我们只希望表中的特定事件有1条记录。
这个问题可能是非常可预测的:一个应用程序线程将读取表,看到事件不存在,插入新事件并提交。但在它提交之前,第二个线程也将读取该表并看到该事件不存在。然后两个线程都将插入事件,我们最终得到同一事件的2条记录。
我想在我们的应用程序中同步访问此特定方法可以防止出现此问题,但Oracle中最好的选择是防止这种情况发生?例如,MERGE会不会阻止这个问题?
答案 0 :(得分:1)
使用DBMS_LOCK定义并获取独占锁定,实现对实现此功能的过程的序列化访问将是微不足道的。
由于读取一致性模型,通过基于SQL的方法进行序列化几乎是不可能的。
答案 1 :(得分:1)
CREATE TABLE EVENTS (ID NUMBER PRIMARY KEY, COUNTER NUMBER NOT NULL);
MERGE INTO EVENTS
USING (SELECT ID, COUNTER FROM DUAL LEFT JOIN EVENTS ON EVENTS.ID = :EVENT_ID) SRC
ON (EVENTS.ID = SRC.ID)
WHEN MATCHED THEN UPDATE SET COUNTER = SRC.COUNTER + 1
WHEN NOT MATCHED THEN INSERT (ID, COUNTER) VALUES (:EVENT_ID, 1);
简单SQL保护每个ID的单个记录,并且无论应用程序触发它还是并发线程数,都会不断增加计数器。您根本不需要编写任何代码,它也非常轻量级。
它也不会产生任何与数据一致性有关的异常,因此您不需要任何特殊处理。
更新:如果两个线程都插入,它实际上会产生唯一的违例异常。我认为第二次合并会切换到更新,但事实并非如此。
更新:刚刚在SQL Server上测试了相同的案例,当并行执行并且记录不存在时,一个MERGE插入,第二个更新。