Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/258.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
Php 原子选择和更新_Php_Oracle_Oracle10g - Fatal编程技术网

Php 原子选择和更新

Php 原子选择和更新,php,oracle,oracle10g,Php,Oracle,Oracle10g,如果我的数据如下所示: ID STATUS DATE_ADDED == ========== ========== 1 Processing 2011-04-01 2 New 2011-04-02 3 New 2011-04-03 4 Processing 2011-04-03 5 Done 2011-04-06 6 New 2011-04-06 7 New 2011-04-14 8 Done

如果我的数据如下所示:

ID STATUS     DATE_ADDED
== ========== ==========
 1 Processing 2011-04-01
 2 New        2011-04-02 
 3 New        2011-04-03
 4 Processing 2011-04-03
 5 Done       2011-04-06
 6 New        2011-04-06
 7 New        2011-04-14
 8 Done       2011-04-14
 ...
。。。在确保任何其他并发进程不能对相同的记录执行相同操作的同时,选择状态为“New”的10条最旧记录并将其状态设置为“Processing”的建议方法是什么


它是一个运行在Windows Server 2003下的PHP/5.2.6上的web应用程序,通过ODBC(Oracle的驱动程序,而不是Microsoft的驱动程序)连接到远程Oracle 10g服务器。

使用事务来完成此操作。为事务使用隔离级别“”将阻止任何其他进程在事务处理行时访问/修改这些行

如果可序列化事务尝试执行SQL数据操作语句,该语句修改任何已被未提交事务修改的表,则该语句将失败

您可能需要使用:

set transaction isolation level serializable;

在Oracle 10g中很难做到这一点。在11g中,
选择更新。。。跳过锁定的
语法使它变得简单

一个简单的
UPDATE
语句将序列化。一个
将选择更新
。当然,两个相互竞争的进程不会得到相同的行;问题是,它们最多只能序列化,最坏的情况下,它们可能会死锁

建议的方法是使用Oracle高级排队(或您选择的排队实现)将要处理的ID排队,并允许排队实现管理值争用

--

SQL可以工作,但如果有人锁定了ORA-00054的范围,第二个用户以相同的偏移量运行该SQL,则该SQL将失败。这可以通过将select封装在一个循环中、捕获ORA-00054错误并使用该错误来增加偏移量来缓解

select * from my_table
 where rowid in 
       (select row_id 
          from (select rowid as row_id, rownum as rn 
                  from mytable where some_condition 
                 order by deterministic_sort_order)
         where rn between :low_rn and :hi_rn
       )
 for update nowait;

排序表达式需要具有确定性(简单地说,包括主键作为排序表达式的结尾),以防止冲突。

您可以创建一个新表并在其中放置一行。然后,您的程序可以使用更新锁定行,或在继续处理原始表之前选择更新。如果所有程序都使用相同的过程来标记表“处理”,则此操作将起作用 插入一行:
插入锁表(应用程序类别)值“APP1”
并提交。这是一次插入。 然后锁定其他会话:
update lock\u Table set usage\u ts=current\u timestamp其中app\u category='CAT1'
您不需要使用列,您可以使用
选择更新


只要您在“选择最早的10个”查询之前进行上述更新,您就可以保证您的结果。我建议将所有内容都放在一个过程中(或将一个过程放在一个包中),以便于应用程序程序员“做正确的事情”。

解决这一问题的一种高压方法是锁定表,以便其他会话无法更新它:
以独占模式锁定您的_表
不幸的是,在释放锁之前,其他会话将无法插入新行,因此这实际上会降低应用程序的并发性。

请注意


此外,乐观锁定策略可用于解决此问题

“可序列化:如果可序列化事务尝试执行SQL数据操作语句,该语句修改未提交事务已修改的任何表,则该语句将失败。”OP不想知道如何让自己的陈述失败。谢谢你的指点。我不知道事务会阻止对受影响行的访问,我将对此进行研究。但是我想我需要先进行
更新
,然后找到一种方法来检索我已更新的精确行。为什么只有您的进程将10个最旧的“新”行更新为“处理”很重要?使用高级排队(AQ)而不是自己滚动?@Catcall-因为记录只需要处理一次。@Shannon separance-我已经在Oracle文档中查看了高级排队。如果我错了,请纠正我,但这看起来是一项令人印象深刻的技术,无法在几个小时内从零开始学习;我希望我有时间:(@lvaro G.Vicario:我不知道怎么回答,我只知道我的办公桌上出现了这样一个要求,我会花一些时间认真研究AQ,然后再开始我自己的工作。但是,我不是站在你的立场上,你知道AQ,调查并决定反对它。我的评论只是为了提醒你看一看,你已经看了。我我一直在玩
SELECT FOR UPDATE
,它看起来很有希望,但我在将它与
ROWNUMBER@Adam马斯克:希望我能在原始答案的基础上再次投票更新后的答案。你不希望在最里面的选择中选择“rownum as rn”。更改“where rn between:low_rn and:hi_rn”到“where rownum”修复此查询的另一种方法是将“rownum as rn”更改为“row_number()(按某个排序顺序按1个顺序划分)“@redcayuga-有效-我在10.2.0.4上检查了它。Rownum从最里面的查询中流出,在order by之后分配,直到之后才被过滤。此外,您不想使用
行号()当
rownum
可以的时候,就结束了。对不起,我不明白。也许你可以给新表和列起个名字,我想…我添加了一个“创建表”和说明。感谢更新,现在我明白了。我实际上有一个类似的
穷人队列
想法,包括一个长的随机字符串和一个
所有者进程\u随机字符串
列:)事实上,您甚至可以在不提交的情况下阻止该行。如果两个并发会话都插入具有相同主键值的行,则“慢一点"会话仍将通过
enq:TX-行锁争用事件阻止。我刚刚更新了您的答案。大多数其他答案提供了出色、可靠和细粒度的机制来完成任务。我甚至在我的开发箱中编写并测试了一个完整的工作原型,它工作起来很有魅力。但当我将其上传到pro时,它什么都不起作用D
create table Lock_Table (
  app_catagory  varchar2(20) primary key,
  usage_ts      timestamp(6)
 );