2017-09-10 54 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'没有启动显式事务,所以它是自动提交的。因此锁不会超过声明的返回。但是这是对你的交易界限是什么的一些猜测。 –