您将哪种 Java 类型用于 JPA 集合,为啥?
Posted
技术标签:
【中文标题】您将哪种 Java 类型用于 JPA 集合,为啥?【英文标题】:Which Java Type do you use for JPA collections and why?您将哪种 Java 类型用于 JPA 集合,为什么? 【发布时间】:2011-06-07 00:35:07 【问题描述】:您在 JPA 域模型中使用以下哪种集合类型以及原因:
java.util.Collection
java.util.List
java.util.Set
我想知道这是否有一些基本规则。
更新 我知道Set
和List
之间的区别。 List
允许重复并具有顺序,Set
不能包含重复元素并且不定义顺序。我在 JPA 的背景下问这个问题。如果您严格遵循定义,那么您应该始终使用 Set
类型,因为您的集合存储在关系数据库中,您不能有重复并且您自己定义了一个顺序,即你的 Java List
不一定保存在数据库中。
例如,我大部分时间都在使用List
类型,不是因为它有订单或允许重复(反正我不能拥有),因为我的组件库中的某些组件需要列表。
【问题讨论】:
我相信您可能会发现@OrderBy 注释有用且有趣。来自 Google 的第一个链接:objectdb.com/api/java/jpa/OrderBy @Grzegorz Oledzki 我知道@OrderBy
注释,但它与List
中的顺序无关。如果您检索您的实体列表(带有@OrderBy
注释),更改其顺序,合并到数据库并再次检索它,您更改的顺序会保留吗?不!您将获得通过@OrderBy
定义的相同订单
我同意这会很棒。但你已经成功了一半。当你阅读这样一个实体时,你会得到正确的排序。
@OrderColumn 注解映射到数据库中的一个顺序列,专门用于在内存中更改元素时保留 List 中元素的顺序。缺点:更改元素的顺序可能会导致更新所有行,以更新顺序列并使其与内存中的顺序保持一致。
【参考方案1】:
就像您自己的问题所暗示的那样,关键是域,而不是 JPA。 JPA 只是一个框架,您可以(并且应该)以最适合您的问题的方式使用它。由于框架(或其限制)而选择次优解决方案通常是一个警钟。
当我需要一套并且从不关心订单时,我使用Set
。如果由于某种原因顺序很重要(有序列表、按日期排序等),则使用 List
。
您似乎很清楚Collection
、Set
和List
之间的区别。使用一个与另一个的唯一原因仅取决于您的需求。您可以使用它们向您的 API 用户(或您未来的自己)传达您集合的属性(可能是微妙的或隐含的)。
这与在整个代码中的其他任何地方使用不同的集合类型所遵循的规则完全相同。您可以使用Object
或Collections
作为所有引用,但在大多数情况下,您会使用更具体的类型。
例如,当我看到List
时,我知道它是以某种方式排序的,并且对于这种情况,重复项要么可以接受,要么无关紧要。当我看到Set
时,我通常希望它没有重复项和特定顺序(除非它是SortedSet
)。当我看到Collection
时,除了包含一些实体之外,我不希望它有任何其他的东西。
关于列表排序...是的,可以保留。即使它不是并且您只使用@OrderBy
,它仍然很有用。想想默认按时间戳排序的事件日志的例子。人为地重新排序列表没有什么意义,但默认排序仍然很有用。
【讨论】:
那么你不应该总是使用Set
吗?因为您将实体存储在关系数据库中,其中不能有任何重复的元素,并且您必须自己定义顺序(即,Java List
中的顺序在持久化时不会保留)。你什么时候使用Collection
?
如有必要,您可以使用人工字段持久化List
订单。但是,在大多数情况下,这是自然的。一个示例可以是某种基于时间的日志,您可以在其中使用@OrderBy("eventDate")。至于Collection
,我会在和Set
类似的情况下使用。
是的,你可以使用和索引列,也可以使用@OrderBy
注解,但是通过这些方式指定的这个顺序与你的Java列表中的顺序无关。您还可以在Set
上使用@OrderBy
注释或使用索引列。而且如果你在你的java列表中改变了顺序,DB中的排序将不会反映在DB中。
查看更新的答案。简而言之,请遵循您在应用程序中其他任何地方使用的完全相同的规则。
我见过一个让水浑浊的案例是JSF。它不支持实体集合的 Set 接口,仅支持 List。这在视图方面很好,但不是存储(通常)。因此,在这种情况下,视图必须是一个列表,不幸的是,它不断地与 Set 相互转换。【参考方案2】:
我认为使用 Set 或 List 的问题要困难得多。至少当您使用 hibernate 作为 JPA 实现时。如果您在休眠中使用 List,它会自动切换到 "Bags" 范例,其中可能存在重复项。
并且该决定对 hibernate 执行的查询有重大影响。这里有一个小例子:
有两个实体,employee 和 company,典型的多对多关系。为了将这些实体相互映射,存在一个 JoinTable(我们称之为“employeeCompany”)。
您在两个实体(公司/员工)上选择数据类型列表
因此,如果您现在决定从 CompanyXY 中删除 Employee Joe,hibernate 会执行以下查询:
delete from employeeCompany where employeeId = Joe;
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXA);
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXB);
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXC);
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXD);
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXE);
现在的问题是:为什么 hibernate 不只是执行那个查询?
delete from employeeCompany where employeeId = Joe AND company = companyXY;
答案很简单(感谢 Nirav Assar 的博文):不可能。在包包的世界中,删除所有并重新插入所有剩余是唯一正确的方法!阅读以获取更多说明。 http://assarconsulting.blogspot.fr/2009/08/why-hibernate-does-delete-all-then-re.html
现在大结论:
如果您在 Employee/Company - Entities 中选择 Set 而不是 List,则不会出现该问题,并且只会执行一个查询!
为什么会这样?因为 hibernate 不再是包的世界(如您所知,Sets 不允许重复)并且现在可以只执行一个查询。
所以 List 和 Sets 之间的决定并不是那么简单,至少在查询和性能方面是这样!
【讨论】:
【参考方案3】:我通常使用列表。我发现 List API 比 Set 更有用,并且与其他库兼容。 List 对于大多数操作和内存来说更容易迭代并且通常更有效。
关系不能有重复且通常不排序这一事实不需要使用 Set,您可以使用对您的应用程序最有用的任何 Collection 类型。
不过,这取决于您的模型,如果您要对它进行大量包含检查,那么 Set 会更有效。
您可以使用@OrderBy 或@OrderColumn 在JPA 中对关系进行排序。
看, http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Ordering
JPA 通常不支持重复,但某些映射(例如 ElementCollections)可能支持重复。
【讨论】:
【参考方案4】:我用:
设置:当集合中的项目没有顺序且唯一时 列表:当商品有订单时【讨论】:
那么你不应该总是使用 Set 吗?因为您将实体存储在关系数据库中,其中不能有任何重复的元素,并且您必须自己定义顺序(即,Java List 中的顺序在持久化时不会保留)。你什么时候使用 Collection?can't be any duplicate elements
是什么意思?当然可以。您只有一个主键作为 Id 字段,其余部分可以重复。
@Theo 在对象上设置相等依赖于 equals 方法。数据库相等完全依赖于主键。这些不一定相同。
@Theo:列表“索引”映射到数据库索引列(并返回)-因此保留列表中的顺序。
@Theo,不,不是。当您在 JPA2 中定义“索引列表”时,来自 java.util.List 的位置被放入该人工列中,原点为 0。因此,列表的顺序被保留......这是透明持久性的全部要点。当你需要排序时,你会使用 List,事实上,不管你的持久化技术是什么【参考方案5】:
https://issues.apache.org/jira/browse/OPENJPA-710
在 List 和 Set 之间进行选择应该会影响查询发送到 DB 的方式。
【讨论】:
能否请您扩展您的答案并简要说明影响是什么? openjpa.208410.n2.nabble.com/… 我已经看到 OpenJPA 在生成的查询中添加额外的 Order By 子句的问题。对于那些不需要任何顺序的查询,这会对数据库的性能产生影响。从上面的链接这应该只在集合被定义为列表时发生。如果它被定义为一个集合,那么这个 Order By 子句将被省略。但不幸的是,无论我选择什么数据类型,我都无法摆脱 Order By 子句。【参考方案6】:我认为在使用 Netbeans 生成实体时使用 Collection 作为通用默认值是一个很好的起点,然后当您弄清楚您的模型实际上是什么并且需要更多功能时,您可以轻松更改它并保持向后兼容。
【讨论】:
以上是关于您将哪种 Java 类型用于 JPA 集合,为啥?的主要内容,如果未能解决你的问题,请参考以下文章
您将使用哪种数据结构:TreeMap 或 HashMap? (Java)[重复]
您将使用哪种数据结构:TreeMap 或 HashMap? (Java)[重复]