我非常了解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
}
}
答案 0 :(得分:0)
您的问题似乎是readers-writers problem的一种风格,它扩展到数据库中的事务。我将创建一个SQL事务类,它主要负责与您的数据库的CRUD操作。然后我会有一个可以锁定的标志,并以与互斥锁非常相似的方式释放,这样你就可以确保没有两个并发进程在它们的关键部分(执行UPDATE或INSERT进入数据库)同一时间。
我也相信有一个readers-writers lock专门用于控制对共享资源的访问,这可能是您感兴趣的。
如果您有任何疑问,请与我们联系!
答案 1 :(得分:0)
正如我在评论中提到的,如果你想要/需要在执行某些Java代码时在数据库行级别进行锁定,那么这段Java代码需要被事务边界包围。例如,如果您通过在服务类中创建一个新方法来实现此目的,那么在该方法中,您将所有需要的Java代码放在&#34; lock&#34;这些行或者如果您通过程序化事务手动完成,直接在控制器代码中由您自己完成。但是,在我看来,你需要具有这种级别的事务划分才能能够锁定&#34;数据库。根据您希望锁定的严格程度,您可以尝试从SERIALIZABLE开始,其中行被锁定以进行读取和写入,并且每个操作都以可序列化的方式一个接一个地完成。