2013-04-08 86 views
1

我目前有一個與Spring Hibernate(通過服務和daoImpl類的註釋事務)的種族問題。以下是我曾經遇到過:春季冬眠插入競爭條件

表:

  • 設備類型:ID(序列),名
  • 設備:ID(序列),device_identifier,device_type_id,IP_ADDRESS

注device_identifier和device_type_id在一起是唯一的

這是我在多線程過程中的一個片段:

if(deviceDao.findByIdentifierAndTypeId(identifier, typeId) == null){ 
     Device newDevice = new Device(); 
     newDevice.setIdentifier(identifier); 
     newDevice.setTypeId(typeId); 
     deviceDao.add(newDevice); 
    } 

所以會發生什麼是,我有透過WebSocket(這裏可能不是重要的細節)監聽設備的服務器,服務器將首先嚐試以確定設備是否已經在數據庫和設備記錄如果尚未找到,則創建。

現在我遇到的問題是服務器可以處理來自設備的多個消息(線程是從設備的每條消息創建的),因此也是競爭條件。

所以,想象這樣的:

設備A發送兩個消息一前一後:

Sends hello message    Sends "here is my ip" message 
      |         | 
      |         | 
      |         | 
    does not see device in DB      | 
     tries to insert    does not see device in DB 
      |        tries to insert 
      Insert completed      | 
           Failed to insert (Unique key constraints not met) 

顯然,當該設備是被插入在第二時間,唯一約束將導致失敗。但我在想,當第一次插入完成時,Spring將能夠接受它並知道當第二個線程再次嘗試插入時它不需要。但儘管我嘗試了各種傳播和隔離模式,但這並沒有發生。我必須錯過一些非常基本的東西,請指出我如何解決這個問題的正確方向。提前感謝您的回覆。如果需要/我會提供更多信息。

回答

1

這是設計行爲。默認情況下,你只會看到提交的行(READ COMMITTED隔離級別)。對於外部進程,您可以將未提交的行視爲還不存在於數據庫中。

最好的解決方案是捕獲唯一約束違規並重試(理想情況下延遲)。您也可以將隔離級別設置爲未提交讀取,但這可能會產生其他競爭條件,我不會推薦這樣做。

+0

謝謝,這就是我最終做的。起初,它似乎不是一種處理它的優雅方式,但是當我更多地考慮它時,除了重試刷新唯一ID之外,確實沒有其他方式。 – 2013-10-09 23:12:57