2012-07-13 126 views
0

我遇到以下问题,如果发生并发请求时出现重复插入。重复插入

我有两个表:

create table tbl (
    val varchar2(1000) 
); 

create table tbl2 (
    val varchar2(1000) 
); 

我只需要在情况下,插入表tbl2一些值,如果表tbl是空的。所以,在我的Java代码我做交易与隔离级别= READ COMMITED:

//start transaction 
int result = jdbcTemplate.queryForInt("select count(*) from tbl"); 
if (result == 0) { 
    int update = jdbcTemplate.update("insert into tbl2(val) values(?)", "di" + UUID.randomUUID().toString()); 
} 
//end transaction 

这里的问题是:有人居然可以插入if (result == 0)和我的更新语句之间的数据。所以我会有重复的条目。

我的例子过于简单化了,但是我的真实情况要复杂得多,但基本的想法是一样的:在插入之前,我需要从Javacode中进行多次选择。因此,如何避免这种情况(我对db端解决方案和java端解决方案感兴趣)?

P.S.数据库是Oracle。

+0

其实我用2个不同的应用程序来模拟这种情况下:从IDE,这里我把断点 Java代码一行“if(result == 0)” 和SQL开发人员在哪里插入新行并提交 – hades 2012-07-13 22:58:14

回答

1

不太确定为什么你想要做你正在做的事情,但你可以先锁定表格。

LOCK TABLE tbl IN SHARE MODE; 

记得提交;释放锁。

+2

ps请仔细选择你的锁定模式:http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9015.htm – AW101 2012-07-13 22:54:05

+0

有没有其他一些好的替代方法来做这些没有锁定表的东西? – hades 2012-07-13 23:03:38

+0

P.S.我想这样做,因为我例如想创建新的订单,以防万一,当有足够的指定类型的项目... – hades 2012-07-13 23:06:04

1

我认为处理这种情况的最好方法可能是在数据库级别。您可以使用查询,如:

insert into tbl2 values(xx) where not exists (select 1 from tbl1) 

所以你的查询可能成为这样的事情

int update = jdbcTemplate.update("insert into tbl2(val) values(?) where not exists (select 1 from tbl1)", "di" + UUID.randomUUID().toString()); 
+0

好点。 但不幸的是我真正的代码使用Hibernate与spring jdbc模板一起使用。 – hades 2012-07-14 10:21:04

+0

嗯,我试过你的解决方案。但我仍然能够重现我的情况 – hades 2012-07-14 12:05:29