初始化或不初始化 JPA 关系映射?
Posted
技术标签:
【中文标题】初始化或不初始化 JPA 关系映射?【英文标题】:To initialize or not initialize JPA relationship mappings? 【发布时间】:2014-01-09 23:53:57 【问题描述】:在一对多 JPA 关联中,将关系初始化为空集合是否被认为是最佳实践?例如。
@Entity
public class Order
@Id
private Integer id;
// should the line items be initialized with an empty array list or not?
@OneToMany(mappedBy="order")
List<LineItem> lineItems = new ArrayList<>();
在上面的例子中,用空ArrayList
的默认值定义lineItems
是否更好?有什么好处和坏处?
【问题讨论】:
【参考方案1】:JPA 本身并不关心集合是否被初始化。当使用 JPA 从数据库中检索订单时,JPA 将总是返回一个带有非空 OrderLines 列表的订单。
为什么:因为 Order 可以有 0、1 或 N 行,最好使用空的、单一大小或 N 大小的集合来建模。如果集合为空,则必须在代码中的任何地方检查它。例如,如果列表为空,这个简单的循环将导致 NullPointerException:
for (OrderLine line : order.getLines())
...
因此,最好通过始终拥有一个非空集合来使其成为不变量,即使对于新创建的实体实例也是如此。这使得创建新订单的生产代码更安全、更清洁。这也使您的单元测试(使用不是来自数据库的 Order 实例)更安全、更清洁。
【讨论】:
我想知道如果你将一个字段声明为final
然后使用惰性获取会发生什么【参考方案2】:
我还建议使用 Guava 的不可变集合,例如,
import com.google.common.collect.ImmutableList;
// ...
@OneToMany(mappedBy="order")
List<LineItem> lineItems = ImmutableList.of();
这个习惯用法从不创建新的空列表,而是重用表示空列表的单个实例(类型无关紧要)。这是函数式编程语言的一种非常常见的做法(Scala 也这样做),并将使用空对象而不是 null 值的开销减少到零,从而使任何效率论据都反对成语没有实际意义。
【讨论】:
但是,对于 JPA 实体,我认为您应该使用 mutable 列表进行初始化,将字段设为私有并且仅为您的集合提供公共 getter。只有这样你才能确定lineItems
永远不是null
。我不会担心创建空列表,因为现代 JVM 非常擅长垃圾收集。作为一般说明:永远不要预先优化您的代码!
我同意@StefanHaberl,您不应该使用不可变集合初始化实体字段。这将使创建新的实体实例和测试变得困难。如果您担心性能,可以尝试new HashSet<>(0)
(***.com/questions/18076492/…) 之类的方法。【参考方案3】:
我更喜欢这样的实用程序:
public static <T> void forEach(Collection<T> values, Consumer<T> consumer)
if (values != null) values.stream().forEach(consumer);
并在如下代码中使用它:
Utils.forEach(entity.getItems(), item ->
// deal with item
);
【讨论】:
【参考方案4】:我的建议是不要初始化它们。
我们遇到了这样一种情况:我们初始化了我们的集合,然后基本上连续两次检索了相同的实体。在第二次检索之后,本应包含数据的延迟加载集合在调用其 getter 后为空。另一方面,如果我们在第一次检索后调用 getter,则集合确实加载了数据。理论上,第二次检索从会话中获得了一个托管实体,该实体的集合已初始化为空,并且似乎已经加载或似乎已被修改,因此没有发生延迟加载。解决方案是不初始化集合。这样我们就可以在事务中多次检索实体,并正确加载其延迟加载的集合。
还有一点需要注意:在不同的环境中,行为是不同的。在同一事务中第二次检索到的实体上调用集合的 getter 时,集合被延迟加载。
很遗憾,我没有关于这两种环境之间有什么不同的信息。看起来——尽管我们没有 100% 地证明这一点,也没有确定实现——不同的 JPA 实现在初始化集合方面的工作方式不同。
我们使用的是休眠 - 只是不知道我们在两个平台上使用的是哪个版本。
【讨论】:
以上是关于初始化或不初始化 JPA 关系映射?的主要内容,如果未能解决你的问题,请参考以下文章