2017-09-10 81 views
3

我正在嘗試編寫一個將在多個服務器上運行但共享單個數據庫以進行金融交易的Web應用程序。是否從postgres數據庫關閉DBI句柄釋放鎖

簡而言之,我想將資金從帳戶A轉移到B.但是可能會有多個請求從同一個帳戶轉帳。

餘額永遠不會爲負數,因此我決定使用SELECT FOR UPDATE來獲取餘額以鎖定行。

我使用JDBI用於向數據庫的連接:http://jdbi.org/

代碼流程如下:

控制器:

DBI dbi = new DBI(datasource); 

..... 
getAccountBalance(); 

.... 

transfer() 

這裏是DOA部分

public int getAccountBalance(String id) { 
     Handle h = dbi.open(); 
     try{ 
      return h.createQuery("SELECT balance FROM accounts " + 
           " WHERE id=:id FOR UPDATE;") 
        .bind("id", id) 
        .mapTo(Integer.class) 
        .first(); 
     } finally { 
      h.close(); 
     } 
    } 

DAO返回餘額,我運行一個餘額檢查s如果可以進行傳輸,然後調用另一種方法來執行傳輸。

public void transfer(String fromAccountId, String toAccountId, int transferAmount) { 
     Handle h = dbi.open(); 
     try{ 
      h.begin(); 
      h.createStatement("UPDATE accounts SET balance = balance - :transferAmount WHERE id = :fromAccountId") 
       .bind("fromAccountId", fromAccountId) 
       .bind("transferAmount", transferAmount) 
       .execute(); 
      h.createStatement("UPDATE accounts SET balance = balance + :transferAmount WHERE id = :toAccountId") 
       .bind("toAccountId", toAccountId) 
       .bind("transferAmount", transferAmount) 
       .execute(); 
      h.commit(); 
     } finally { 
      h.close(); 
     } 
    } 

我的問題是,如果我關閉句柄在getAccountBalance()將其發佈在該行的鎖挑選出的?如果是這種情況,我如何持有鎖?我是DBI的新手。謝謝

回答

3

它實際上是在h.close(),h.commit()之前發佈的。行鎖不會超出提交。

如果你需要通過提交保持鎖,你可以使用諮詢鎖,但它們有點尷尬,而不是我推薦這樣的東西。

否則請詳細閱讀pessimistic vs optimistic locking。另見Optimistic vs. Pessimistic locking

+0

我在方法A中創建了鎖,但在方法B中進行了提交。那仍然保持鎖嗎?對不起,如果我以前沒有正確解釋它。 –

+0

@AmitVig我不知道你的'dbi'對象是什麼,或者它的'open'方法是什麼,所以很難回答這個問題。重點是*一個鎖持續到獲取它的事務提交*爲止。如果你的第一個方法仍然持有這個鎖,並且你的第二個方法在一個單獨的DBI連接中被調用,它將無限期地阻塞第一個事務的鎖。或者,如果您在同一個連接的同一個打開的事務中調用它,它會發出一個關於已經打開的事務的警告,但是否則工作正常。 –

+0

所以*在瘋狂猜測*,'getAccountBalance'沒有啓動顯式事務,所以它是自動提交的。因此鎖不會超過聲明的返回。但是這是對你的交易界限是什麼的一些猜測。 –