【问题标题】:Hibernate/Dropwizard: Find or create with @UnitOfWork does not workHibernate/Dropwizard:使用@UnitOfWork 查找或创建不起作用
【发布时间】:2015-03-17 17:08:14
【问题描述】:

我们有一个使用 dropwizard 编写的 rest API。 API 的一项功能是创建以下形式的事件三元组:userID - action - itemID 如果此 userID/itemID 组合还没有任何操作,我们将创建一个新事件。对应的资源函数有@UnitOfWork注解:

@POST
@UnitOfWork
@Timed
public Event createEvent(Event event) {
    return eventDAO.updateOrCreate(event);
}

如果这是此特定 userID 或 itemID 的第一个事件,我们将分别创建一个用户或一个项目。这是物品的功能(用户相同):

public Item getOrCreate(Event event) {
    Item item = findOne(event.getItemId());
    if(item == null) {
        item = new Item();
        item.setItemId(event.getItemId());
        create(item);
    }
    return item;
}

问题是我们有重复的项目(即,如果我们强制 itemId 是唯一的,则会出现错误)。如果我们在这样的不同线程中有两个请求

user1 action1 item1
user2 action2 item1

似乎两者都试图创建一个。从@UnitOfWork 的documentation 中,我们假设所有内容都将包含在事务中,因此不应该发生这种情况。 当我们添加 itemId 应该是唯一的数据库约束时,我们得到一个 PSQL 异常“重复键值违反唯一约束...”。

我错过了什么?

【问题讨论】:

  • 通过查看@UnitOfWork 代码,您可以看到它为每个请求创建新会话并且事务绑定到该会话。所以它不适用于你的情况。
  • 但为什么不呢?我想要的不是一次交易和一次交易中的所有内容吗?
  • 因为当您同时有 2 个请求时,您不在一个会话中,@UnitOfWork 将为您创建两个单独的会话。所以一个事务发生在一个会话中,而另一个事务发生在另一个会话中。

标签: java hibernate postgresql transactions dropwizard


【解决方案1】:

限制 HTTP 请求的事务不会阻止您描述的问题。您没有向数据库提供任何关于它应该使用什么来防止双重插入的指示。除非有数据库约束表明事件 ID 应该是唯一的,否则数据库无法判断它是在不同请求中创建的同一实体。

我从您给出的描述中假设您对数据库没有这样的限制。如果是这种情况,请添加一个,然后看看会发生什么。如果不是这种情况,您可能需要使用事件表使用的架构更新您的帖子。

【讨论】:

  • 感谢您的回答。我添加了有关约束的信息。
【解决方案2】:

事务不会自动锁定行,这是阻塞其他线程/请求所必需的。您需要使用 LockMode.PESSIMISTIC_WRITE 或类似名称来完成此操作。

【讨论】:

    猜你喜欢
    • 2023-03-16
    • 2014-04-26
    • 1970-01-01
    • 2014-04-27
    • 2017-02-27
    • 2013-12-17
    • 2013-05-26
    • 2018-04-12
    • 1970-01-01
    相关资源
    最近更新 更多