Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oracle中连续的应用程序线程和未提交的数据_Oracle_Concurrency - Fatal编程技术网

Oracle中连续的应用程序线程和未提交的数据

Oracle中连续的应用程序线程和未提交的数据,oracle,concurrency,Oracle,Concurrency,我们的应用程序从Oracle“事件”表中读取一条记录。当事件记录存在时,我们更新该记录的“计数”字段。如果记录不存在,我们就插入它。因此,对于表中的特定事件,我们只需要一条记录 这个问题很可能是可以预测的:一个应用程序线程将读取表,看到事件不在那里,插入新事件并提交。但在提交之前,第二个线程也将读取该表,并看到事件不存在。然后两个线程都将插入该事件,我们将得到同一事件的两条记录 我想在我们的应用程序中同步访问此特定方法可以防止此问题,但Oracle中防止此问题的最佳选项是什么?例如,合并是否总是

我们的应用程序从Oracle“事件”表中读取一条记录。当事件记录存在时,我们更新该记录的“计数”字段。如果记录不存在,我们就插入它。因此,对于表中的特定事件,我们只需要一条记录

这个问题很可能是可以预测的:一个应用程序线程将读取表,看到事件不在那里,插入新事件并提交。但在提交之前,第二个线程也将读取该表,并看到事件不存在。然后两个线程都将插入该事件,我们将得到同一事件的两条记录


我想在我们的应用程序中同步访问此特定方法可以防止此问题,但Oracle中防止此问题的最佳选项是什么?例如,合并是否总是可以防止此问题?

序列化对实现此功能的过程的访问将非常容易实现,使用它来定义并获取独占锁

由于读取一致性模型,通过基于SQL的方法进行序列化实际上是不可能的

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不会保护它,因为它在与任何其他SQL语句完全相同的读取一致性模型下运行,无论如何,这不是一个原子操作。@Husqvik和David-这是两个截然相反的答案:-)事实上,我认为David说问题仍然存在是正确的,因为即使使用MERGE,第二个合并查询也不会看到第一个合并的未提交更改(也称为read_committed isolation),对吧?当然假设原子声明,那么它就安全了。因为一个合并更新/插入行应该锁定另一个合并,直到完成,所以第二个合并将使用实际数据。当然,您需要有唯一的约束,以确保序列化到事件记录。@Husqvik,由一个会话进行的插入行的合并不涉及任何会阻止另一个会话发出相同合并的锁。更新总是序列化的,插入也涉及唯一约束。可能有一种方法可以使用唯一约束和捕获异常等,当然,您希望在可能的情况下设置独特的约束来保护数据。但是,在API中提供一个显式的序列化机制是非常简单和轻量级的。我在我的问题中没有提到这一点,但我们每天只希望每个事件类型(字符串)(日期字段)有一条记录。这将很难在唯一约束中捕获。您可以根据(Trunc(my_date),event_type)创建一个唯一的基于索引的函数,这样就可以了。在这种情况下更简单,因为您可以提前为第二天创建事件记录,因此,这将确保行存在,并且您只需简单的更新就可以一致地递增计数器。是的,正如Tom Kyte在这里解释的那样,如果您想要避免数据不一致的可能性或需要处理由唯一约束引发的错误,您必须序列化。