【发布时间】:2014-07-30 14:31:36
【问题描述】:
我非常了解SELECT ... FOR UPDATE 方法,但稍后通过同一连接更新时它确实有效。
但是放在应用程序上下文中,情况并不多,因为数据库管理器使用连接池。我想从数据库中获取记录,它们被锁定在下面的控制器中,在没有其他控制器可以读取或更新它们的情况下处理它们,完成工作后更新它们并释放锁定。该怎么做?
我正在使用 Spring JDBCTemplate 并有以下几个类:
ItemDao:
@Service
public class ItemDao extends AppDao {
// this is supposed to lock the row
public UserItems getItemsForUpdate(long userId) {
return jdbcTemplate.queryForObject("select * from tbl_items where ownerId = ?", new UserItemsRowMapper(), userId);
}
public void updateItems(UserItems items) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(items);
oos.close();
byte[] data = baos.toByteArray();
jdbcTemplate.update("update tbl_items set data = ? where id = ?", new Object[] { data, items.getId() });
} catch (Exception e) {
logger.error(e);
}
}
}
Web 端点处理程序:
@Controller
public class EnergyFillHandler extends BaseItemsUpdatedHandler<EnergyFillRequest> {
@RequestMapping(value="/energyFill", method=RequestMethod.POST)
public @ResponseBody List<BaseResponse> handle(@RequestBody EnergyFillRequest json) {
UserItems items = itemDao.getItems(u.getId());
... do something; if someone else calls getItems
he needs to be blocked at this point
itemDao.updateItems(userItems);
... items are now released and anyone can read and obtain lock on them
}
}
【问题讨论】:
-
如果我在这里没有遗漏任何明显的东西,请将您的服务设为
@Transactional并设置适当的隔离级别。不知道你的情况,但我认为你可以使用Isolation.SERIALIZABLE。 -
实际上,您需要确保此代码:
UserItems items = itemDao.getItems(u.getId()); itemDao.updateItems(userItems);包含在单个SERIALIZABLE事务中。 -
好的,很好,但是所有这些操作都发生在 EnergyFillHandler 中,它是一个公开的 Web 端点,它无法访问任何事务管理器,因为它们在 DAO 中占有一席之地
-
但是它可以访问 dao。是什么阻止你让你的 dao 交易?
-
对不起,我不明白。在 EnergyFillHandler 中,我调用了 DAO 的两个方法——一个获取结果,然后它做一些工作,然后它调用 DAO 的另一个方法来更新 EnergyFillHandler 所做的事情。问题是我应该如何进行事务处理,因为实际工作发生在 DAO 之外。如果您发布一些示例,我将不胜感激
标签: mysql spring transactions jdbctemplate