如何锁定MySQL行并在应用程序上下文中稍后发布
我很清楚如何锁定MySQL行并在应用程序上下文中稍后发布,mysql,spring,transactions,jdbctemplate,Mysql,Spring,Transactions,Jdbctemplate,我很清楚SELECT。。。对于更新方法,但在以后通过同一连接进行更新时它确实起作用。 然而,在应用程序上下文中,情况并非如此,因为数据库管理器使用连接池。我想从数据库中获取记录,它们被锁定在下面的控制器中,在没有其他控制器可以读取或更新它们的情况下处理它们,完成工作后更新它们并释放锁。怎么做 我使用的是Spring JDBCTemplate,有以下几个类: 项目DAO: @Service public class ItemDao extends AppDao { // this is
SELECT。。。对于更新
方法,但在以后通过同一连接进行更新时它确实起作用。
然而,在应用程序上下文中,情况并非如此,因为数据库管理器使用连接池。我想从数据库中获取记录,它们被锁定在下面的控制器中,在没有其他控制器可以读取或更新它们的情况下处理它们,完成工作后更新它们并释放锁。怎么做
我使用的是Spring JDBCTemplate,有以下几个类:
项目DAO:
@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
}
}
@控制器
公共类EnergyFillHandler扩展BaseItemsUpdatedHandler{
@RequestMapping(value=“/energyFill”,method=RequestMethod.POST)
public@ResponseBody列表句柄(@RequestBody EnergyFillRequest json){
UserItems=itemDao.getItems(u.getId());
…做点什么;如果其他人调用getItems
他需要在这一点上被阻止
itemDao.updateItems(userItems);
…物品现在被释放,任何人都可以读取并获得锁
}
}
您的问题似乎是从数据库扩展到事务的一种味道。我将创建一个SQL事务类,它主要负责数据库的CRUD操作。然后我会有一个标志,它可以以非常类似于互斥锁的方式被锁定和释放,这样你就能够确保没有两个并发进程同时处于它们的关键部分(执行数据库的更新或插入)
我还相信有一个专门处理控制对共享资源的访问的方法,这可能会引起您的兴趣
如果您有任何问题,请告诉我 正如我在评论中提到的,如果您希望/需要在执行某些Java代码时锁定数据库行级别,那么该段Java代码需要被事务边界包围。例如,如果您通过在服务类中创建一个新方法来实现这一点,并且在该方法中放置所有需要“锁定”这些行的Java代码,或者如果您通过编程事务手动实现,则直接在控制器代码中实现,这取决于您自己。但是,在我看来,您需要有这种级别的事务划分才能“锁定”数据库。根据锁定的严格程度,您可以尝试从SERIALIZABLE开始,其中行被锁定以进行读写,并且每个操作都以可序列化的方式一个接一个地完成。如果我没有遗漏任何明显的内容,使您的服务具有事务性,并设置适当的隔离级别。我不知道您的场景,但我认为您可以使用
Isolation.SERIALIZABLE
。实际上,您需要确保以下代码:UserItems items=itemDao.getItems(u.getId());itemDao.updateItems(userItems)代码>被包装在一个可序列化的事务中。好的,很好,但是所有这些操作都发生在EnergyFillHandler中,它是一个公开的web端点,它无法访问任何事务管理器,因为它们位于DAOSB,但它可以访问dao。是什么阻止你把dao变成事务性的?对不起,我不明白。在EnergyFillHandler中,我调用了DAO的两个方法——一个获得结果,然后它做一些工作,然后它调用DAO的另一个方法来更新EnergyFillHandler所做的工作。问题是,既然实际工作发生在DAO之外,我应该如何使它成为事务性的。如果你能举一些例子,我将不胜感激