盒装vs原始类型作为实体ID

时间:2018-08-01 22:16:57

标签: java database hibernate jpa orm

在JPA(Hibernate实现)中,哪种类型最好用作实体ID: 装箱类型(例如Integer)还是未装箱类型(例如int)?

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

但是我实体的ID为int,并且运行良好,没有任何错误,我们知道原始实例变量的默认值为0。因此他说,也许休眠将0视为特殊对象,并假定该对象是一个新对象。

6 个答案:

答案 0 :(得分:10)

似乎Current Documentation 建议使用盒装字体。

  

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

答案 1 :(得分:7)

好吧,我们使用非基元,我们有很强的理由。例如,我们的很多字段int/Integer的绝对业务价值都是zero,这是完全有效的。例如,考虑一个债务字段-如果该字段为zero,那就好了,这意味着您没有债务。

问题在于,使用基元时,默认值为零-因此您可能会意外忘记例如通过setDebt对其进行设置,因此它可能会以一个你从来没有打算去那里。因此,我们将Integer与某些验证结合使用,例如,这些验证绝对不能为null。但是,即使我们忘记添加适当的验证,该代码也可能会以NullPointerException(最好在测试中) break 中断,并且我更喜欢Exception,而不是数据库中的不一致值。

答案 2 :(得分:2)

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

使用Cmobilecom JPA测试了这两种情况,并且效果很好。当然,没有任何性能差异。

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

答案 3 :(得分:1)

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

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;

答案 4 :(得分:0)

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

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

答案 5 :(得分:-2)

我们可以这样想:

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

程序运行并评估 x 时,假设它评估为 实际的Int(不是底部)。然后在将来任何时候x被评估时, 而不是重做整个计算,我们只想获取值 是我们先前计算出来的。

我们要做的是替换为重击(计算) 用一个thunk计算x,该thunk仅返回原为 之前计算过。

问题在于,以后每次需要获取x时, 跟随该指针指向返回值的(简单)代码。这个 如果您经常需要这些值,则会变得昂贵。

输入未装箱的值。未装箱的值只是该低值,而不是 包裹在一个大块的里面。这意味着严格意义上 在程序未必死的情况下不能被未定义。