2017-09-10 7 views
3

Ich versuche, eine Webanwendung zu schreiben, die auf mehreren Servern ausgeführt wird, aber eine einzelne Datenbank für finanzielle Transaktionen gemeinsam nutzen.Schließt DBI Freigabesperre von Postgres-Datenbank

In einfachen Worten möchte ich Geld von Konto A zu B übertragen. Aber es könnte mehrere Anfragen sein, Geld von dem gleichen Konto zu überweisen.

Das Guthaben kann niemals negativ sein, daher entschied ich mich, SELECT FOR UPDATE zu verwenden, um das Guthaben zu holen, um die Zeile zu sperren.

Ich verwende JDBI für eine Verbindung mit der Datenbank: http://jdbi.org/

Der Code Fluss wird wie folgt dar:

Controller:

DBI dbi = new DBI(datasource); 

..... 
getAccountBalance(); 

.... 

transfer() 

Hier die DOA Teil

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(); 
     } 
    } 

Der DAO gibt den Saldo zurück, ich führe einen Saldo-Check durch ee, wenn die Übertragung durchgeführt werden kann und dann eine andere Methode aufrufen, um die Übertragung durchzuführen.

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(); 
     } 
    } 

Meine Frage ist, wenn ich den Griff in getAccountBalance() schließt er die Sperre freigeben auf die Zeile sie ausgewählt? Wenn das der Fall ist, wie halte ich das Schloss? Ich bin neu bei DBI. Danke

Antwort

3

Es ist tatsächlich vor der , unter h.commit() freigegeben. Zeilensperren werden nicht länger als festgeschrieben gespeichert.

Wenn Sie Sperren benötigen, die nach dem Commit gehalten werden, können Sie Advisory Locks verwenden, aber sie sind ein bisschen peinlich und nicht etwas, das ich für so etwas empfehlen würde.

Sonst lesen Sie bitte auf pessimistic vs optimistic locking. Siehe auch Optimistic vs. Pessimistic locking.

+0

Ich erstelle die Sperre in Methode A, aber commit in Methode B. wird das immer noch die Sperre halten? Entschuldigung, wenn ich es vorher nicht richtig erklärt habe. –

+0

@AmitVig Ich weiß nicht, was dein 'dbi'-Objekt ist oder was seine' offene' Methode macht, also ist es schwer, das zu beantworten. Der Punkt ist, dass * eine Sperre gehalten wird, bis die Transaktion, die sie erworben hat, festgeschrieben ist *. Wenn Ihre erste Methode immer noch die Sperre enthielt und Ihre zweite Methode innerhalb einer separaten DBI-Verbindung aufgerufen wird, würde sie die Sperre der ersten Transaktion auf unbestimmte Zeit blockieren. Oder wenn Sie es innerhalb der gleichen offenen Transaktion auf der gleichen Verbindung aufrufen, würde es eine Warnung über eine bereits geöffnete Transaktion ausgeben, ansonsten aber in Ordnung. –

+0

Also * bei einer wilden Schätzung *, 'getAccountBalance' startet keine explizite Transaktion, also ist es autocommitted. Das Schloss wird somit nicht über die Rückgabe der Aussage hinaus gehalten. Aber das macht einige Vermutungen darüber, was Ihre Transaktionsgrenzen sind. –

Verwandte Themen