日期:2014-05-19  浏览次数:20731 次

谁帮我解决一下Oracle读脏数据的问题?
案例说明:火车票售票系统
同时启动多个线程模拟买票
窗口首先查询出还剩余多少张票,判断是否足够,再进行更新操作
所以是一条select语句,一条update语句

现在出现的问题:
第一个人买首先查询剩余20张,买了2张,update为18张
第二个人在update之前就读出了,所以他读出的剩余票数也是20张,买了2张,update为18张

结果买了4张,确只减少了2张

请问如何解决这个问题呢?
或者遇到这种问题是怎么处理的(java)
不用synchronized锁方法

------解决方案--------------------
探讨

现在用select...for update解决了
select的时候加锁了

------解决方案--------------------
探讨

引用:

引用:

现在用select...for update解决了
select的时候加锁了

这种方式可能会有问题。
如果不是存储过程,for update之后,程序当掉了,没有commit,则其他针对于该表的操作都会idle直到该连接被重置。


那该如何处理 用for update(n……

------解决方案--------------------
这种肯定多并发的系统,
在开始检出数据的时候就用for update nowait应该是不合适的,
虽然可以排他,但是系统使用的友好度就大大降低了。
因为这样的话,
所有除了操作数据的人之外的人都会被挡回来。

不知道在update之前,
用一个select for update nowait这样的查询来确认一下数据库中的数据可不可以。
虽然是个悲观锁,但是也算是最小化了。

比如:
select1(检索出有几张票)
画面操作1
画面操作2
画面操作3
select2 ... for update nowait(先检索一下看看和上次的数据是否一致,并且是否被别人锁表)
update(出错就回画面,不出就commit)

占地学习
帮顶

good luck
------解决方案--------------------
其实你用FOR UPDATE虽然能解决问题,也可以通过事务的序列化完成,但是他们都会出现异常,用异常去控制流程一般是不推荐的,我可以等一会,如果不行再说,所以我一般应对类似的问题会做一下操作:

方法一:
在JAVA程序中调用存储过程的时候,有一个共享对象,Boolean类型,代表该对象是否正在被调用,synchronized控制对对象的访问,顺序调用该过程,或者用易失变量判定,若发现被调用,此时设置为wait()指导当前调用者将它notify操作。

方法二:
判定不要直接使用for update,我习惯这样使用:
SELECT count(1) into COUNTER FROM test WHERE id=<关键字> FOR UPDATE NO WAIT SKIP LOCKED;
此时你可以获取COUNTER的值是否为0,如果为0代表正在操作,这个怎么操作就你自己决定了,让记得ROLLBACK和COMMIT。。。。。
付:FOR UPDATE NO WAIT SKIP LOCKED该SQL或根据查询条件并跳过被锁住的行,所以如果被锁住了,就不会得到结果,当然COUNTER就为0了,如果得到值,说明你要操作的数据还没有被加锁,此时可以继续操作那条数据了,因为这个线程获取到了这个锁。。。

还有就是UPDATE的时候应当以当前值进行修改,如
UPDATE test
set num = num - <卖掉的数量>
WHERE id = <关键字>;