2016-01-22 65 views
2

我在一家@Stateless休息資源與Wildfly和MySQL

  1. 線程A正在讀一Account實體上WildFly 9.0.2執行不可重複讀隔離級別不可重複讀隔離級別,打印的平衡然後做一些其他的工作(睡眠)。
  2. 線程B進來並讀取相同的Account實體,打印餘額並通過calculateBalance()方法計算餘額,然後更新實體。它再次讀取實體並打印出餘額。
  3. 線程A然後讀取實體並打印出餘額。

根據我對Non-Repeatable讀取級別的理解,線程B應該阻塞直到線程A完成完成(退出事務/無狀態休息資源)。

這裏是打印輸出:

  • 線程A:printBalance = 500
  • 線程B:printBalance = 500
  • 線程B:printBalance = 600
  • 線程A:printBalance = 500

從那我可以看到線程B不阻塞,即使線程A仍然忙,也可以運行。

下面是代碼:

@GET 
    @Path("/{accountId}/{threadName}") 
    public Response calculcateBalance(@PathParam("accountId") Long accountId, @PathParam("threadName") String threadName) { 

     Account account = em.find(Account.class, accountId); 
     printBalance(account,threadName); 

     if ("ThreadA".equals(threadName)) { 
      sleepSeconds(10); 
     } else if ("ThreadB".equals(threadName)) { 
      account.calculateBalance(); 
      em.merge(account); 
     } 

    account = em.find(Account.class, accountId); 
    printBalance(account,threadName); 

    return Response.ok().build(); 
} 

如果我更改隔離級別爲序列的所有塊。

我對不可重複讀的理解是否錯誤?在線程A完成之前線程B是否被阻塞?

回答

2

它取決於底層的數據庫系統。如果您使用SQL Server,默認情況下使用2PL,則線程A將在讀取該行時獲取共享鎖,並且線程B將阻止寫入該行(直到線程A釋放共享鎖)。

Oracle,PostgreSQL和MySQL使用MVCC,而可重複讀取不使用鎖定,因爲讀者不會阻止編寫者,編寫者也不會阻止讀者。 在MVCC中,檢測到異常,並且如果線程B修改了該行,則線程A將檢測到該更改並中止其事務。

所以,在MVCC中,anomalies are detected rather than prevented

+0

嗨弗拉德,我認爲這正是發生的事情。我正在連接到一個MySQL數據庫。因此,爲了檢測實體是否發生了變化,我需要在Account實體上添加'@ Version'? – Rentius2407

+0

對於讀取已提交,這是正確的。對於可重複讀取,缺省更新將被檢測到。無論如何,即使在[多請求邏輯事務](http://vladmihalcea.com/2014/09/22/preventing-lost-updates-in-long-conversations/)中,樂觀鎖定也能檢測到丟失的更新。 –

+0

我需要MySQL上的任何配置來檢測它嗎?我不認爲它正在檢測丟失的更新。 – Rentius2407