在Hibernate映射中使用包装类Integer或基本类型int

50

我所在的公司正在进行一项重要讨论,即在Hibernate中将原始类型直接映射到实体和表格(POJOs)中,还是使用包装类(java.lang.Integer、java.lang.Long)。

我们的目标是确保这些值在数据库中不为空。

倾向于使用原始类型的理由:

  • 将这些值处理为int类型可以确保它们永远不会为null,从而防止在字段上意外获取空引用。
  • int类型只需要32/64位内存,而Integer则需要16字节内存并且速度较慢。

倾向于使用包装对象的理由:

  • 我们可以在数据库级别添加约束来始终防止出现null值。
  • 如果用户没有设置值,我们可能会得到0而不是null,在数据库中会导致误导性数据,难以捕捉错误数据。
  • 对象比原始类型更具表现力。 我们既有null值又有integer值,因此可以使用注释(例如javax.validation.constraints.NotNull)更轻松地验证它们。

1
你可以使用Hibernate来完成所有这些操作,而无需使用JSR303。虽然JSR303很好,是向前迈出的正确一步,但它也有局限性,而Hibernate则可以解决这些问题。如果你使用包装器,最终会出现许多getIntValue和Parse等语句,代码看起来会很混乱。不要使用包装器。 - Shahzeb
5个回答

47

使用包装器,让生活更简单。

您的数据模型应该决定这一点。无论如何,您都应该在数据库中强制执行可空性。

如果它们在数据库中可为空,则使用包装器。如果它们不可为空,并且您使用包装器,则如果尝试将null插入到数据库中,将会引发异常。

如果您的数据模型没有指定,请遵循惯例,在所有情况下都使用包装器。这样人们就不必考虑或决定0值表示null。

我还要质疑您的说法,即这可能会降低性能。您有测量过吗?我的意思是真正进行了测量吗?当您与数据库交互时,有许多考虑因素,而不仅仅是16位和32位之间的差异。

只需使用简单、一致的解决方案。除非有人给出了一个极好的理由(并提供准确的测量统计数据)要求您采用其他方式,否则请在任何地方都使用包装器。


我赞同“在数据库中应该强制使用nullability”,但我认为包装器会让事情变得复杂,不是简单化。 - Shahzeb

16

需要指出的是:

Hibernate建议(4.1.2节)在持久化类中使用非基本数据类型属性,实际上指的是标识符属性

4.1.2. 提供标识符属性

Cat类有一个名为id的属性。此属性映射到数据库表的主键列。该属性可以被任意命名,其类型可以是任何基本数据类型、任何基本数据类型的"包装器"类型、java.lang.String或java.util.Date。

...

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

然而,基本数据类型的优势并不明显:

  1. 在属性中拥有不一致的非空值比NullPointerException更糟糕,因为这种潜在的错误难以追踪:从编写代码到检测到问题经过的时间更长,可能会在完全不同的代码环境中显示出来。
  2. 关于性能:在测试代码之前,通常是过早考虑。安全性应该放在第一位。

这仍然是Hibernate 5.1的建议,但现在它在“2.5.5.提供标识符属性”部分中。 - Night Owl

7
Hibernate文档(只是我找到的第一个版本)说明如下:

属性可以被任何名称所代替,其类型可以是任何原始类型、任何基本类型的“包装”类型、java.lang.String或java.util.Date。

...

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

因此,“专家之声”建议使用Integer/Long等...但是为什么要这样做并没有被描述。
我想知道是否这样做是为了在创建尚未持久化的对象时可以不使用标识符(即属性值为null),以区分已持久化的实体。

0
我要冒昧地不同意这里的其他答案。如果数据库中的字段可以为空,就使用包装类型。如果它不能为null,就使用基本类型。这样你既能获得性能优势,又能更容易区分哪些字段可以为null,哪些字段不可以在你的代码中。

0

如果你正在使用像mongo db这样的数据库,或者数据在null时具有意义,请使用包装类型

提示:如果你要进行计算,只需创建一个额外的空值检查 getter,并在整个代码库中使用它来避免空值检查。

如果数据点必须始终具有值且不能为null,请使用原始类型


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接