先描述一下场景: 假设我有一张表 orders(id, order_id, money, type), 每次我选择某一个订单的最后一笔进行消耗。例如,现在表里有一条记录(3, 777, 34.00, 1),我现在要消耗 2.00 ,先把原来的记录查出来并update成(3, 777, 34.00, 0), 然后insert一条新的记录(4, 777, 32.00, 1)。
现在如果如果我的服务部署在多台机器上,就有可能两个并发连接同时取到同一条记录,然后在这条记录上消耗。比如,现在两个连接同时取到记录(3, 777, 34.00, 1),然后具体的消耗代码我放在事务中做,但是仍会得到结果记录为
(3, 777, 34.00, 0)
(4, 777, 32.00, 1)
(5, 777, 32.00, 1)
而如果正常消耗的话应该为
(3, 777, 34.00, 0)
(4, 777, 32.00, 0)
(5, 777, 30.00, 1)
我的业务代码使用 java 写的,必须先查上次最后的记录,然后具体的消耗的时候,即 update 和 insert 语句放到事务 里做,用的 read committed 隔离级别。
给出一个 pseudocode in Java
last = getInfoByOrderId(orderid, type);
//...
// 使用 last 先进行一些业务判断,如果不满足一些条件就直接报错返回了
//...
TransactionTemplate.execute(new TransactionCallback() {
String sql = "select * from " + last.getTableName() + " where id = " + last.getId() + " for update";
lastinfo = queryByIdForUpdate(sql);
update(lastinfo);
insertOneItem(consumeMoney);
});
业务场景有点复杂,望见谅:D ,对于这种并发场景,有没有好的处理方式?
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.