如何锁定MySQL行并稍后在应用程序上下文中释放

时间:2014-07-30 14:31:36

标签: mysql spring transactions jdbctemplate

我非常了解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
    }
}

2 个答案:

答案 0 :(得分:0)

您的问题似乎是readers-writers problem的一种风格,它扩展到数据库中的事务。我将创建一个SQL事务类,它主要负责与您的数据库的CRUD操作。然后我会有一个可以锁定的标志,并以与互斥锁非常相似的方式释放,这样你就可以确保没有两个并发进程在它们的关键部分(执行UPDATE或INSERT进入数据库)同一时间。

我也相信有一个readers-writers lock专门用于控制对共享资源的访问,这可能是您感兴趣的。

如果您有任何疑问,请与我们联系!

答案 1 :(得分:0)

正如我在评论中提到的,如果你想要/需要在执行某些Java代码时在数据库行级别进行锁定,那么这段Java代码需要被事务边界包围。例如,如果您通过在服务类中创建一个新方法来实现此目的,那么在该方法中,您将所有需要的Java代码放在&#34; lock&#34;这些行或者如果您通过程序化事务手动完成,直接在控制器代码中由您自己完成。但是,在我看来,你需要具有这种级别的事务划分才能能够锁定&#34;数据库。根据您希望锁定的严格程度,您可以尝试从SERIALIZABLE开始,其中行被锁定以进行读取和写入,并且每个操作都以可序列化的方式一个接一个地完成。