在我完成之前阻止其他会话读取数据
我有一张桌子可以容纳来自不同公司的客户,例如:
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。是不是递增的数字,它是一个字母数字字符串。
答案 0 :(得分:2)
据我所知,您无法阻止其他会话读取数据。 Oracle和其他一些数据库之间的区别之一是作者不会阻止读者。
我可能会稍微看一下这个。我假设您生成下一个foo_code
的方式是确定性的。如果在company_id, foo_code
上添加唯一索引,那么您可以让应用程序在循环中尝试插入:
如果两个会话同时尝试此操作,则第二个会话将尝试插入相同的foo_code
并将获得唯一的约束违规。这被困住并处理得很好,它只是再次尝试;可能多次,直到它得到一个干净的插入。
你可能有一个DB程序在循环中尝试插入,但是因为你想在PHP中生成新值,所以循环也在PHP中也是有意义的,尝试一个简单的插入。
如果您有大量插入物并且可能发生冲突,则这不一定能很好地扩展。但是,如果您希望同一个客户的同时插入很少,并且只是在发生这种情况时必须处理奇怪的情况,这将不会增加太多开销。