oracle 并发问题??

fuyou001 2010-01-13 10:08:21
我现在有1至20 个客户端要访问oralce 数据一的同一张表 假设表为a

但客户端是java写的程序

每个程序是要做的是从a中取出一条数据去处理,并修改下这条数据的状态

怎么防止客户端取到同一条数据,重复处理

用java 同步已经不可能,因为是多个JVM,没办法 控制同步

在数据库方面有什么方法

我想到的是select ...for update
但用这个,假设一个客户端在处理取,另一个客户端也能取到同样的记录
???
有什么好方法

...全文
217 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
wh62592855 2010-01-14
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 crazylaa 的回复:]
楼主用存储过程实现。
存储过程第一句就是
select ××,××,rowid from tble where status='未处理' and rownum =1 for update
下面根据rowid来处理update。
[/Quote]恩……这个方法可以考虑一下
使用rownum来进行限制
不过最好加个排序 不然返回数据的顺序每次可能会有所不同
可是加了排序会不会变慢啊 呵呵 楼主自己根据实际情况权衡一下
horizonlyhw 2010-01-14
  • 打赏
  • 举报
回复
我感覺 還是用“邏輯”卡住吧。 比如就像樓主那種加字段的方式。
因為你想控制的就是 “查詢不能重複”,那倒不如用邏輯 事先就把數據的區域分開
SambaGao 2010-01-14
  • 打赏
  • 举报
回复
java 读出数据库肯定做不到实时性。
oracle的行级锁。应该不用考虑这些吧。
wh62592855 2010-01-13
  • 打赏
  • 举报
回复
其实ORACLE加锁也就是你在update的那一小段时间里会加

比如说某个员工select出了一条数据
可能他要看个10分钟 再做决定
而update肯能1秒钟就完成了

可问题是在他看的10分钟内会不会有其他用户已经处理了这条记录了……
呵呵 暂时没想出太好的办法
wh62592855 2010-01-13
  • 打赏
  • 举报
回复
就用你的那个方法吧
加一个字段 让每个员工针对不同范围内的数据进行处理
zjcxy3150 2010-01-13
  • 打赏
  • 举报
回复
建议增加个字段,查询都可以查询,在更新之间先判断状态是否为已经处理,如果处理给出提示,否则进行更新操作。我也遇到你这样的情况,我就是这样处理的,这样还行吧
suiziguo 2010-01-13
  • 打赏
  • 举报
回复
1 个人认为,应该有其他条件,设置各自处理各自的记录。比如,根据地区,本地区处理本地区的。这只是个例子。你加字段,也是这个目的。冒昧说句,表及业务组合设计时有欠缺。
2 既然没有其他条件,就好比批处理模式了。但若需要人工判断处理,显然批处理模式不合适。
fuyou001 2010-01-13
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 suiziguo 的回复:]
有0-20个客户端

客户端要要做的就是取出a中状态为末处理的一条记录去分析,
分析完成后,再把状态修改在处理成功

每个客户端进入表后取记录,都只是根据status='末处理'来取吗?没有其他过滤条件?
你在更新状态前,需要分析,需要时间,此时你只是分析该条记录,如果不锁定改记录,则其他client肯定可以修改甚至锁定之。
在处理期间,锁定它先。这样防止你在分析期间,其他client也来处理它。
[/Quote]
没有其它条件了
就只根据status ='末处理'来取数据

如果分析时锁定,其它client 不能取数据了

所我想在再个字段clientId ,这样取数据时就status ='末处理' and clientId ='client1'
这样可以解决
还有没有其它可行的办法
studying_ 2010-01-13
  • 打赏
  • 举报
回复
假定程序 是这样: 1 :String querySql = select * from a for update
suiziguo 2010-01-13
  • 打赏
  • 举报
回复
有0-20个客户端

客户端要要做的就是取出a中状态为末处理的一条记录去分析,
分析完成后,再把状态修改在处理成功

每个客户端进入表后取记录,都只是根据status='末处理'来取吗?没有其他过滤条件?
你在更新状态前,需要分析,需要时间,此时你只是分析该条记录,如果不锁定改记录,则其他client肯定可以修改甚至锁定之。
在处理期间,锁定它先。这样防止你在分析期间,其他client也来处理它。
雪狼__ 2010-01-13
  • 打赏
  • 举报
回复
遇到过这样的问题,没有想出什么好办法,关注中
fuyou001 2010-01-13
  • 打赏
  • 举报
回复
客户端是
java 程序用jdbc 访问数据库 表a

有0-20个客户端

客户端要要做的就是取出a中状态为末处理的一条记录去分析,
分析完成后,再把状态修改在处理成功


如果同时访问 ,可能客户端会取到我是重复的数据
比如说: client1 取了a中 id 为1的记录
client2 也有可能会取到id 为 1的记录

现在要解决就是防止客户端取重复的记录

想到一个笨方法就是在a增加一个字段clinetId表示客户端的 client1...
然后 client1 只取clientId为client1的记录
client2 只取clientId为client2的记录....

不知道还有什么好方法


suiziguo 2010-01-13
  • 打赏
  • 举报
回复
放在同一事务里?
此时它们属于同一session,querySql可以看见本session的脏数据。
我不知道你到底想实现什么功能,可否描述下你的需求?
fuyou001 2010-01-13
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 suiziguo 的回复:]
1  如果你select * from a for update ,则锁定所有记录。你想再update  a set status = 60 ,除非前面的事务提交,否则你想都别想!

2 querySql有ORACLE一致性读要保证,不会读取在你发起query后才提交的数据。

故你应该多看看ORACLE锁及UNDO部分的内容。
我只是告诉你,不会发生你所说的情况,不过另外一个倒是可能,那就是死锁。
死锁纯属业务逻辑问题,无论是数据库设计,还是程序逻辑,都要注意!
[/Quote]
我把 1,2放到同一事务里,可行吗?
suiziguo 2010-01-13
  • 打赏
  • 举报
回复
select * from a for update本身就有问题。
它是一个悲观锁,你把锁人工扩大了。一个事务里需要处理多少数据,就锁定多少数据。
像你这样锁定整个表,本来就是你想独占此表,也就是exclusive方式。
for update where ……
仅锁顶你需要处理的记录,则其他记录可以被其他会话修改。
fuyou001 2010-01-13
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 suiziguo 的回复:]
1  如果你select * from a for update ,则锁定所有记录。你想再update  a set status = 60 ,除非前面的事务提交,否则你想都别想!

2 querySql有ORACLE一致性读要保证,不会读取在你发起query后才提交的数据。

故你应该多看看ORACLE锁及UNDO部分的内容。
我只是告诉你,不会发生你所说的情况,不过另外一个倒是可能,那就是死锁。
死锁纯属业务逻辑问题,无论是数据库设计,还是程序逻辑,都要注意!
[/Quote]
这样说select * from a for update 的话, 我后面就没办法修改状态 了,除非前面的事件提交或roolback了
那就有什么办法解决这个问题
suiziguo 2010-01-13
  • 打赏
  • 举报
回复
当然,1中前面事务回滚,后面事务也能成功,呵呵。
suiziguo 2010-01-13
  • 打赏
  • 举报
回复
1 如果你select * from a for update ,则锁定所有记录。你想再update a set status = 60 ,除非前面的事务提交,否则你想都别想!

2 querySql有ORACLE一致性读要保证,不会读取在你发起query后才提交的数据。

故你应该多看看ORACLE锁及UNDO部分的内容。
我只是告诉你,不会发生你所说的情况,不过另外一个倒是可能,那就是死锁。
死锁纯属业务逻辑问题,无论是数据库设计,还是程序逻辑,都要注意!
fuyou001 2010-01-13
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 suiziguo 的回复:]
使用select ...for update nowait
此时 假设一个客户端在处理取,另一个客户端也能取到同样的记录,则立即报错,无须等待。
[/Quote]
假定程序 是这样: 1 :String querySql = select * from a for update ; //这样就取出来了
2: String updateSql = update a set status = 60 马上我就把这样记录的状态可修改了
但在这1 和2 语句 间,另一个客户端正在执行querySql

那这样就可能会取重复了啊

suiziguo 2010-01-13
  • 打赏
  • 举报
回复
使用select ...for update nowait
此时 假设一个客户端在处理取,另一个客户端也能取到同样的记录,则立即报错,无须等待。
加载更多回复(2)

17,086

社区成员

发帖
与我相关
我的任务
社区描述
Oracle开发相关技术讨论
社区管理员
  • 开发
  • Lucifer三思而后行
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧