【问题标题】:Boxed vs primitive type as entity id盒装与原始类型作为实体 id
【发布时间】:2023-03-13 20:26:01
【问题描述】:

在 JPA(Hibernate 实现)中,哪种类型更适合用于实体的 id: 盒装类型(例如Integer)还是未装箱类型(例如int)?

朋友说应该使用 Boxed 类型,因为当你在程序中创建一个新实体时,Hibernate 看到 id 是 null 并理解它应该在数据库中创建一个新行(相反如果 id 不是nullHibernate 可能会更新数据库中的现有行。

但是我的实体的 id 是 int,它运行良好,没有任何错误,我们知道原始实例变量的默认值是 0。所以他说也许hibernate将0视为特殊对象,并假设该对象是一个新对象。

【问题讨论】:

    标签: java database hibernate jpa orm


    【解决方案1】:

    似乎Current Documentation推荐使用盒装类型。

    我们建议您在持久类上声明一致命名的标识符属性,并使用可空(即非原始)类型。

    【讨论】:

      【解决方案2】:

      嗯,我们使用非基元,我们有充分的理由这样做。我们的许多字段,例如int/Integer,其绝对商业价值为zero,是完全有效的。例如,考虑一个债务字段 - 如果该字段是 zero,那就更好了,这意味着您没有债务。

      问题在于,对于原语,零是默认值 - 因此您可能会不小心忘记通过 setDebt 设置它,因此它可能以您从未使用过的值到达您的数据库打算去那里。出于这个原因,我们使用Integer 和一些不应该为空的验证,例如;但即使我们忘记添加正确的验证,该代码也可能会中断 NullPointerException(最好在测试中),我更喜欢异常而不是数据库中的不一致值。

      【讨论】:

      • 这个答案没有解决这个问题。该问题专门询问@Id 字段。您可以通过仅以 1 开始序列(这是 Hibernate 中的默认行为)来避免将 0 作为有效数字。
      【解决方案3】:

      我们可以这样想:

      当我们有一个值 x :: Int 时,'x' 是一个计算 评估时将返回 Int 或将 是底部(未定义)。

      当程序运行并评估 x 时,假设它评估为 实际 Int(不是底部)。那么在未来任何时候 x 被评估, 而不是重做整个计算,我们只想得到这个值 我们之前计算出来的。

      我们要做的就是替换 thunk(计算) 使用 thunk 计算 x,该 thunk 只返回原来的值 之前计算过。

      问题是每次你需要在未来得到 x 时,你有 跟随这个指针指向返回值的(平凡的)代码。这 如果您经常需要这些值,就会变得昂贵。

      输入未装箱的值。未装箱的值只是那个低级别的值,而不是 包裹在一个thunk里面。这意味着它在某种意义上是严格的 如果你的程序一定会死掉,就不能 undefined。

      【讨论】:

        【解决方案4】:

        对于实体 id,原始(例如 int)和它的包装器(例如 Integer)之间没有区别。根据 JPA 规范,两者都是有效的。 JPA 提供者足够聪明,可以跟踪实体的状态和生命周期。当实体 id 为 0(原始类型)或 NULL(包装器类型)时,如果配置了 id 生成器,JPA 提供程序将为实体生成一个 id。如果 id 是自动生成的,则零不被视为有效的实体 id。

        Cmobilecom JPA 测试了这两种情况,效果同样好。当然,没有发现性能差异。

        免责声明:我是Cmobilecom JPA 的开发人员,这是一个适用于 Java 和 Android 的轻量级 JPA 实现。

        【讨论】:

          【解决方案5】:

          我更喜欢实体模型中的盒装类型,因为这样可以灵活地在泛型中使用盒装类型。 例如,这里的实体模型只能具有扩展为可序列化的类型作为 id。稍后在服务层将很有用,我们可以对主键执行各种操作。

          public interface BaseEntity<E extends Serializable> extends Serializable {
            E getId();
          }
          

          实体模型可能是这样的:

          @Entity
          public class PhoneNumber implements BaseEntity<Long> {
            private static final long serialVersionUID = 1L;
          
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "PHONE_NUMBER_ID")
            private Long id;
          

          【讨论】:

            【解决方案6】:

            实体和集合的唯一标识符可以是除二进制、blob 和 clob 之外的任何基本类型。 (也允许使用复合标识符,见下文。)

            基本值类型在 org.hibernate.Hibernate 上定义了相应的 Type 常量。例如,Hibernate.STRING 表示字符串类型。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-12-16
              • 1970-01-01
              • 2016-06-16
              • 2012-07-02
              • 1970-01-01
              • 2015-02-22
              相关资源
              最近更新 更多