Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何锁定MySQL行并在应用程序上下文中稍后发布_Mysql_Spring_Transactions_Jdbctemplate - Fatal编程技术网

如何锁定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之外,我应该如何使它成为事务性的。如果你能举一些例子,我将不胜感激