防止其他会话读取数据,直到我完成

时间:2014-07-09 07:39:31

标签: sql oracle oracle10g

在我完成之前阻止其他会话读取数据

我有一张桌子可以容纳来自不同公司的客户,例如:

CUSTOMER
    CUSTOMER_ID
    COMPANY_ID
    CUSTOMER_NAME
    FOO_CODE

当我插入或更新客户时,我需要根据现有的(在公司内部)计算FOO_CODE。

如果我这样做:

SELECT MAX(FOO_CODE) AS GREATEST_CODE_SO_FAR
FROM CUSTOMER
WHERE COMPANY_ID=:company_id

...然后用客户端语言(PHP)生成代码,最后发出INSERT / UPDATE,我知道如果其他程序实例获取相同的GREATEST_CODE_SO_FAR,我可能会遇到竞争条件。

是否可以在表上发出行级锁定,以便尝试读取属于给定公司的任何客户的FOO_CODE列的其他会话被延迟,直到我提交或回滚我的交易吗


我失败的尝试:

  • 此:

    SELECT MAX(FOO_CODE)
    FROM CUSTOMER 
    WHERE COMPANY_ID=:company_id
    FOR UPDATE
    

    ...触发器:

      

    ORA-01786:不允许更新此查询表达式

  • 此:

    SELECT FOO_CODE
    FROM CUSTOMER 
    WHERE COMPANY_ID=:company_id
    FOR UPDATE
    

    ...检索所有公司行,甚至不会阻止其他会话读取数据。

  • LOCK TABLE ......好吧,文档几乎没有任何示例,我无法弄清楚语法

P.S。是不是递增的数字,它是一个字母数字字符串。

1 个答案:

答案 0 :(得分:2)

据我所知,您无法阻止其他会话读取数据。 Oracle和其他一些数据库之间的区别之一是作者不会阻止读者。

我可能会稍微看一下这个。我假设您生成下一个foo_code的方式是确定性的。如果在company_id, foo_code上添加唯一索引,那么您可以让应用程序在循环中尝试插入:

  • 获取您当前的最大值
  • 计算新代码
  • 执行插入
  • 如果您没有违反约束条件,请退出循环
  • 否则继续循环的下一次迭代并重复该过程

如果两个会话同时尝试此操作,则第二个会话将尝试插入相同的foo_code并将获得唯一的约束违规。这被困住并处理得很好,它只是再次尝试;可能多次,直到它得到一个干净的插入。

你可能有一个DB程序在循环中尝试插入,但是因为你想在PHP中生成新值,所以循环也在PHP中也是有意义的,尝试一个简单的插入。

如果您有大量插入物并且可能发生冲突,则这不一定能很好地扩展。但是,如果您希望同一个客户的同时插入很少,并且只是在发生这种情况时必须处理奇怪的情况,这将不会增加太多开销。