2016-07-06 33 views
0

我希望我能解釋得很好,因爲我的問題非常依賴於時間。所有灰熊工作者想要插入(SQL)首先插入灰熊,第二個SQLIntegrityConstraintViolationException

我有一個客戶端發送數據到服務器(Java)。在服務器上,我有一個RestServer等待來自客戶端的輸入。

當客戶端向服務器發送數據時,它會多次發送這些數據,直到它從服務器收到「okay-response」。 不幸的是,服務器的這個「OK」可能需要一些時間,因爲當服務器從客戶端獲取數據時,他必須在客戶端收到響應之前做很多事情(插入到數據庫中...)。

但是在服務器上的灰熊員工的工作時間內,客戶端再次向服務器發送數據,並且服務器上的下一個灰熊工人(灰熊工人數字2開始),並嘗試將其插入到數據庫中。

發生這種情況是因爲在灰熊工作人員2啓動之前,灰熊工人尚未完成插入數據庫並檢查數據是否已存在於數據庫中。灰熊工作者二認爲「沒有數據沒有插入數據庫,因此我要插入」。

希望我的照片能展現我所試圖解釋: multithreading problem

兩個工人認爲他們必須插入到數據庫中,雖然灰熊工人一人仍然試圖插入到數據庫。

我該如何告訴灰熊工作者,已經有一名灰熊工人試圖插入數據庫?

或者我該如何阻止灰熊工人兩秒? 或者我該如何解決這個問題?

只有代碼,你可以在圖片中看到:

public void setPunkteFuerTanz(Wertung eineWertung) 
     throws SQLException, ClassNotFoundException 
{ 
    int anzahlPunkteIDs; 
    Integer runde = eineWertung.getRunde(); 
    if(runde == 0) 
    { 
     //something to do here 
    } 

    /*Jurorid 1 ist Admin, der darf mehrere Zeilen schreiben, deshalb 
    *anzahlPunkteIDs immer 0 */ 
    if(eineWertung.getJurorID() == 1) 
    { 
     anzahlPunkteIDs = 0; 
    } 
    else 
    { 
     anzahlPunkteIDs = Integer.valueOf(sqlFunctions.getResultFromCustomQuery(
      "select count(punkteid) from punkte " 
      .concat("where jurorid=").concat(String.valueOf(eineWertung.getJurorID())) 
      .concat(" and tid=").concat(String.valueOf(eineWertung.getTanzID())) 
      .concat(" and runde=").concat(String.valueOf(runde))).toString());    
    } 

    if(anzahlPunkteIDs == 1) 
    { 
     //Tanz schon bewertet 
     sqlFunctions.setExecuteUpdate("UPDATE PUNKTE SET " 
      .concat("choreo=").concat(String.valueOf(eineWertung.getChoreo())) 
      .concat(",technik=").concat(String.valueOf(eineWertung.getTechnik())) 
      .concat(",level=").concat(String.valueOf(eineWertung.getLevel())) 
      .concat(",gesamt=").concat(String.valueOf(eineWertung.getGesamt())) 
      .concat(",futuretalent=").concat(String.valueOf(eineWertung.getFutureTalent())) 
      .concat(",bestchoreo=").concat(String.valueOf(eineWertung.getBestChoreo())) 
      .concat(",bestcostume=").concat(String.valueOf(eineWertung.getBestCostume())) 
      .concat(",runde=").concat(String.valueOf(runde)) 
      .concat(" where jurorid=").concat(String.valueOf(eineWertung.getJurorID())) 
      .concat(" and tid=").concat(String.valueOf(eineWertung.getTanzID())) 
      .concat(" and runde=").concat(String.valueOf(runde))); 
    } 
    else 
    { 
     //Tanz noch nicht bewertet 
     int letztePunkteID; 
     Object letztePunkteIDObject = 
       this.sqlFunctions.getResultFromCustomQuery("select punkteid from punkte"); 

     letztePunkteID = (letztePunkteIDObject == null) ? 
       0 : (Integer.valueOf(letztePunkteIDObject.toString())+1); 

     this.sqlFunctions.setExecuteUpdate("insert into punkte " 
      .concat("(punkteid,jurorid,choreo,technik,level,gesamt,") 
      .concat("futuretalent,bestchoreo,bestcostume,runde,tid) ") 
      .concat("values(").concat(String.valueOf(letztePunkteID)).concat(",") 
      .concat(String.valueOf(eineWertung.getJurorID())).concat(",") 
      .concat(String.valueOf(eineWertung.getChoreo())).concat(",") 
      .concat(String.valueOf(eineWertung.getTechnik())).concat(",") 
      .concat(String.valueOf(eineWertung.getLevel())).concat(",") 
      .concat(String.valueOf(eineWertung.getGesamt())).concat(",") 
      .concat(String.valueOf(eineWertung.getFutureTalent())).concat(",") 
      .concat(String.valueOf(eineWertung.getBestChoreo())).concat(",") 
      .concat(String.valueOf(eineWertung.getBestCostume())).concat(",") 
      .concat(String.valueOf(runde)).concat(",") 
      .concat(String.valueOf(eineWertung.getTanzID())).concat(")")); 

// UPDATE 由於同步沒有工作,我試圖與合併查詢的提示。 由於我的合併聲明對於評論太長,所以我會在此更新它: 我想我已經通過合併查詢來完成它。取而代之的INSERT語句我寫了這個查詢:`

MERGE INTO punkte pu USING 
    (VALUES 1,2,3,1,5,5,5,5,5,5,5) temp (punkteid, tid,jurorid,runde,choreo,technik,level,gesamt,futuretalent,bestchoreo,bestcostume) 
    ON temp.punkteid = pu.punkteid 
    WHEN MATCHED THEN UPDATE SET 
    pu.punkteid=temp.punkteid,pu.tid = temp.tid,pu.jurorid=temp.jurorid,pu.runde=temp.runde,pu.choreo=temp.choreo,pu.technik=temp.technik,pu.level=temp.level,pu.gesamt=temp.gesamt,pu.futuretalent=temp.futuretalent,pu.bestchoreo=temp.bestchoreo,pu.bestcostume=temp.bestcostume 
    WHEN NOT MATCHED THEN 
    INSERT (punkteid, tid,jurorid,runde,choreo,technik,level,gesamt,futuretalent,bestchoreo,bestcostume) VALUES (temp.punkteid, temp.tid,temp.jurorid,temp.runde,temp.choreo,temp.technik,temp.level,temp.gesamt,temp.futuretalent,temp.bestchoreo,temp.bestcostume)` 

//更新2

是的,謝謝大家的努力,它正在與「合併」就像一個魅力。

也是一個非常bigh感謝和信Gadellaa他的耐心,通過其他可能的解決方案

+0

您應該使用hsqldb的Merge執行「upsert」操作。當該行不存在時,它會插入。當它存在時它會更新。 http://hsqldb.org/doc/2.0/guide/dataaccess-chapt.html#dac_merge_statement –

+0

您必須使用MERGE語句作爲第一條評論的建議。這可以讓數據庫引擎用單個語句處理不同的情況。 – fredt

回答

0

跟我走你可以使自己的交易。有一個數據庫字段,鎖定它,確保你有鎖定,然後做你的東西。

看着你(加入)的代碼示例,它很可能是這樣的:

public void setPunkteFuerTanz(Wertung einWertung) { 
    try{ 
     this.sqlFunctions.setExecuteUpdate("select * from LOCKTABLE for update"); 
     // if we get here, we have a mutex 
     // all your original code then goes here 

    } catch(SomeExceptionWhichOccursWhenLockingTimesOut e) { 
     // do nothing 
    } 
} 

另一種選擇是靜態塊上同步。只要這兩個線程運行在同一個JVM中,就可以在函數週圍使用一個synchronized(Object.class) { ... },該函數也應該鎖定。

+0

這對我有什麼幫助? 我發現這篇文章解釋交易: http://www.mkyong.com/jdbc/jdbc-transaction-example/ 它很好,如果我有幾個後面的sql語句,一個失敗,我可以輕鬆地回滾。 但我想我還有另外一種情況:我有兩個工作人員正在做同樣的事情(插入)。如果兩方都嘗試插入,交易如何幫助我? 另外,如果事務1將阻塞另一個事務,只要事務一被完成,工作者2(事務二)仍將嘗試插入到數據庫中。 –

+0

工作人員將嘗試插入它,但它會*知道*它在那裏。就好像它昨天發生的一樣,而不是僅僅幾微秒之前。但是可以保證沒有其他人在搞數據庫。如果你的程序目前不支持這一點,它也應該開始這樣做(但我收集,它可能會) –

+0

你不標記你想要的更新插入,但沒有完全相關的東西,爲此創建。這會獲得鎖定。 基本上,你正在創建一個你需要啓動的特殊令牌。考慮去購物(執行你當前的代碼),這是說你需要有一張有效的停車票才能進入商場,而且只有一個停車位。所以第一個去公園就可以買到票。其他人必須等待,直到你離開,然後別人可以停車併購物。任何人離開都保證已經完成購物不受其他人的干擾 –