我正在尝试编写一个 Web 应用程序,它将在多个服务器上运行,但共享单个财务交易数据库。
简单来说,我想从账户 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();
}
}
The DAO(去中心化自治组织)返回余额,我进行余额检查以确定是否可以进行转账,然后调用另一个方法来执行转账。
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还不熟悉。谢谢。
getAccountBalance
没有启动显式事务,因此它是自动提交的。因此,在语句返回后,锁定不会保持。但这是对您的事务边界做出一些猜测。 - Craig Ringer