2012-07-13 99 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