【问题标题】:JPA 2 merge is inserting instead of updating when primary key is UUID当主键为 UUID 时,JPA 2 合并正在插入而不是更新
【发布时间】:2019-05-14 22:53:09
【问题描述】:

对于我的一个实体,我想使用 UUID 作为主键而不是 Long。实体扩展了 AbstractEntityUUID:

@MappedSuperclass
public abstract class AbstractEntityUUID implements Serializable {

    private static final long serialVersionUID = 40076842287035126L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID id;

    public UUID getId() {
        return id;
    }

    @Override
    public int hashCode() {
        if (getId() != null) {
            return getId().hashCode();
        }
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        AbstractEntityUUID other = (AbstractEntityUUID) obj;
        if (getId() == null || other.getId() == null) {
            return false;
        }
        if (!getId().equals(other.getId())) {
            return false;
        }
        return true;
    }

}

实体本身是:

@Entity
@Table(schema = "schemaName", name = "order")
@DynamicUpdate
public class Order extends AbstractEntityUUID {

    private static final long serialVersionUID = 6358231835578038565L;

    @Column(precision = 10, scale = 2)
    protected BigDecimal itemPrice;

    @Temporal(TIMESTAMP)
    @Basic(fetch = LAZY)
    protected Date purchaseDate;

    // other properties and getters & setters ...

}

persist 方法工作正常:

Order order = new Order();
order.setItemPrice(BigDecimal.ONE);
order = getEM().persist(order);

使用正确信息在数据库表上创建一个新行。以后有合并的时候就是问题发生的时候:

order.setPurchaseDate(new Date());
order = getEM().merge(order);

上一行似乎保持不变,并使用包含价格和日期的新主键创建了一个新行。

当主键为 Long 且 GenerationType.IDENTITY 时,行将正确更新,并且按预期工作。

这是在 WildFly 16 服务器上的 ejb 3 bean 上运行的。 Hibernate 的实现似乎是 5.3.9。数据库是 MySQL 服务器 5.7。

如果 Java 生成 UUID 值很好,我宁愿不更改它,除非需要使实体使用 UUID 作为主键。

【问题讨论】:

  • 在这种情况下,如果实体在 .persist 或 .find 之后处于持久状态,则无需调用合并。当事务准备好提交时,Hibernate 将刷新更改。但我不确定为什么它在您的代码中没有按预期工作。
  • @arseniyadru 这是正确的。但是在同一个用例中,当实体具有 Long as PK 时,它会按预期工作。这只发生在 PK 是按照描述实现的 UUID 时。
  • id 实际生成的时间不清楚。您是否在代码中生成 UUID(未显示)?如果您依靠休眠来生成 UUID,我希望注释更像@GeneratedValue(generator = "uuid") @GenericGenerator(name = "uuid", strategy = "uuid")
  • @Cascader 我已经有了注释 javax.persistence.GeneratedValue ,似乎我无法为其添加额外的属性 generator = "uuid"。 GenericGenerator 是特定于 Hibernate 的,我目前仅尝试使用 JPA 进行这项工作。

标签: java hibernate ejb jpa-2.0


【解决方案1】:

当 MySql 生成 UUID 时,您确定持久化按预期工作吗?实体的id和插入数据库的id一样吗?

【讨论】:

  • 这似乎是另一个有趣的发现。坚持之后,当我执行 entityManager.find(entityClass, id) 时,即使该行是在 MySQL 中创建的,它也不会返回任何内容。当我查询该行独有的另一个属性时,我收到实体并且它们具有相同的 id(用 equals 测试)。通过 ID 查找的默认 entityManager.find(...) 方法似乎不适用于 UUID 或可能的错误。
  • 你是对的,UUID 作为 ID 与 MySQL 结合是行不通的。实体被持久化(断言 entity.id 不为 null),但通过 entiy.id 查找返回 null。使用 JPA 2.2、HBN 5.3.10 和 MySQL 5.7.26 复制。顺便说一句:与 H2 相同的设置工作正常。
  • 感谢您确认这一点。 JPA 中的 UUID 已经存在了很长一段时间。如果我很快找不到解决方案,我将向 Hibernate 提交错误报告。
  • 还有一点需要注意,在我的设置中,HBN 会创建架构并选择二进制作为 ID 列的数据类型。
  • 对我来说也一样。它为 MySQL 中的 PK 创建一个 BINARY(255)。
猜你喜欢
  • 1970-01-01
  • 2011-07-03
  • 2017-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-14
  • 2016-06-07
  • 2016-04-23
相关资源
最近更新 更多