1

我刚从 JPA 开始,我有一个很可能是愚蠢的问题,但如果是,这意味着 JPA 有一些相当基本的东西!如果这是一个愚蠢的问题,请原谅我,但我无法在任何地方找到答案。

我想为我的表的主键自动生成 UUID,我已经阅读了很多关于如何执行此操作的内容,并阅读了所有关于 ID 在对象被持久化之前不可用的警告以及这如何影响 equals 和 hashCode方法,但我想出了一个我看不到问题的解决方案,但我很怀疑,因为我无法在网络上的任何地方找到对该方法的任何参考!

方法很简单:

  1. 实现一个 @PrePersist 方法,如果 ID 字段为空,则设置它。
  2. 在返回值之前为调用 @PrePersist 方法的 ID 实现一个 getter。
  3. 实现 hashCode 和 equals 以便它们使用 getter 来获取 ID,而不是直接访问字段。

在我看来,这可能很简单,这似乎可以解决所有问题,但我必须遗漏一些东西,否则肯定会有到处使用这种方法的例子!

4

3 回答 3

0

此解决方案存在一些问题:

  • 如果您的 getter 将调用@PrePersist回调,则 Id 将在意外时间设置,而不会引起任何人注意。更改 getter 中的对象是您应该避免的副作用的一个很好的例子。

  • 如果您的应用程序负责在持久化之前分配 ID,您将遇到@PrePersist激活回调但实体未持久化的情况(例如不利的 TX 回滚)。

  • 这些问题将使您无法可靠地区分持久对象和非持久对象。

于 2013-11-05T10:20:31.933 回答
0

一些东西:

1) Artem 是正确的,首先要做的是让自己成为一个静态 UUID 生成器。我个人使用JUG如下:

private static TimeBasedGenerator uuidGen = Generators.timeBasedGenerator(EthernetAddress.fromInterface());

public static String next() {
    String uuid = uuidGen.generate().toString();
    return uuid;
}

2)@PrePersist当您创建一个新对象并通过 Web 服务(例如 REST/SOAP)对其进行序列化时,您的方法有一天会失败,因为您将在事务完成之前对其进行序列化(否则您会遇到可怕的 Hibernate 延迟初始化错误)。所以你经常需要在保存之前设置Id。我为此使用吸气剂副作用。

3)将副作用放在你的getter中很好,就像你把你的JPA注释放在字段上而不是属性访问器上一样。

4)您的哈希码不能单独依赖 Id,因为有时 Hibernate 会反序列化您的对象并在初始化之前将其添加到 HashMap 中。这很少见,但今晚发生在我身上,这就是我发现你的问题的方式。所以我的哈希码现在是:

final public int hashCode() {
    return id == null ? getClass().hashCode() : id.hashCode();
}

到目前为止,这运行良好并通过了所有单元/集成测试。

于 2014-01-15T05:56:46.610 回答
0

我认为您更容易使用单独的静态方法(在单独的类中),它将为您执行实体 id 的初始化。

只需使用UUID.random()为您的 POJO/Entity 提供唯一的 String,然后将其与 PersistenceContext 合并,以便 id 反映在数据库中。

于 2013-11-05T10:32:23.483 回答