日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Hibernate事实:有利于双向集vs列表

發(fā)布時(shí)間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Hibernate事实:有利于双向集vs列表 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Hibernate是一個(gè)很棒的ORM工具,它極大地簡(jiǎn)化了開(kāi)發(fā),但是如果您想正確地使用它,則有很多陷阱。

在大中型項(xiàng)目中,雙向父子關(guān)聯(lián)非常常見(jiàn),這使我們能夠?yàn)g覽給定關(guān)系的兩端。

在控制關(guān)聯(lián)的持久/合并部分時(shí),有兩個(gè)可用選項(xiàng)。 其中將有負(fù)責(zé)同步收集變化的@OneToMany結(jié)束,但是這是一個(gè)低效率的做法,這是很好的描述在這里 。

最常見(jiàn)的方法是@ManyToOne端控制關(guān)聯(lián)并且@OneToMany端使用“ mappedBy”選項(xiàng)時(shí)。

我將討論后一種方法,因?yàn)榫蛨?zhí)行的查詢(xún)數(shù)量而言,這是最常見(jiàn),最有效的方法。

因此,對(duì)于雙向集合,我們可以使用java.util.List或java.util.Set。

根據(jù)Hibernate docs的說(shuō)法,列表和文件包比集合更有效。

但是當(dāng)我看到以下代碼時(shí),我仍然感到焦慮:

@Entity public class Parent {...@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", orphanRemoval = true) private List children = new ArrayList()public List getChildren() { return children; }public void addChild(Child child) { children.add(child); child.setParent(this); }public void removeChild(Child child) { children.remove(child); child.setParent(null); } }@Entity public class Child {...@ManyToOne private Parent parent;public Parent getParent() { return parent; }public void setParent(Parent parent) { this.parent = parent; } }Parent parent = loadParent(parentId); Child child1 = new Child(); child1.setName("child1"); Child child2 = new Child(); child2.setName("child2"); parent.addChild(child1); parent.addChild(child2); entityManager.merge(parent);

這是因?yàn)樵谧罱迥曛?#xff0c;當(dāng)在父關(guān)聯(lián)上調(diào)用合并操作時(shí),我一直在插入重復(fù)的子代。 發(fā)生這種情況是由于以下問(wèn)題: HHH-3332和HHH-5855 。

我最近一直在測(cè)試一些Hibernate版本,并且仍然在3.5.6、3.6.10和4.2.6版本上進(jìn)行復(fù)制。 因此,經(jīng)過(guò)5年在許多項(xiàng)目上看到這一點(diǎn)后,您了解了為什么我對(duì)使用列表與集合持懷疑態(tài)度。

這是在運(yùn)行復(fù)制此問(wèn)題的測(cè)試用例時(shí)得到的結(jié)果,因此添加兩個(gè)子級(jí),我們得到:

select parent0_.id as id1_2_0_ from Parent parent0_ where parent0_.id=? insert into Child (id, name, parent_id) values (default, ?, ?) insert into Child (id, name, parent_id) values (default, ?, ?) insert into Child (id, name, parent_id) values (default, ?, ?) insert into Child (id, name, parent_id) values (default, ?, ?)

僅當(dāng)合并操作從父級(jí)到子級(jí)聯(lián)時(shí),才會(huì)出現(xiàn)此問(wèn)題,并且存在以下變通辦法:

  • 合并孩子而不是父母
  • 在合并父母之前先讓孩子堅(jiān)持
  • 從父級(jí)刪除Cascade.ALL或Cascade.MERGE,因?yàn)樗挥绊懞喜⒉僮?#xff0c;而不影響持久化操作。

但是所有這些都是黑客,在大型項(xiàng)目中很難遵循,因?yàn)樵S多開(kāi)發(fā)人員都在相同的代碼庫(kù)上工作。

因此,我的首選方式是使用Set,即使有時(shí)它們的效率不如Lists更好,但是由于我一直偏愛(ài)正確性與性能優(yōu)化,因此最好使用Set。

當(dāng)涉及到這類(lèi)問(wèn)題時(shí),最好具有代碼約定,因?yàn)樗鼈円子谔砑拥巾?xiàng)目開(kāi)發(fā)指南中,并且易于記憶和采用。

使用集合的一個(gè)優(yōu)點(diǎn)是,它迫使您定義適當(dāng)?shù)膃quals / hashCode策略(該策略應(yīng)始終包括實(shí)體的業(yè)務(wù)密鑰。業(yè)務(wù)密鑰是一種字段組合,該字段組合在父級(jí)的子級(jí)中是唯一的或唯一的,并且甚至在之前也是一致的)以及將實(shí)體持久保存到數(shù)據(jù)庫(kù)中之后)。

如果您擔(dān)心會(huì)失去以添加孩子的相同順序保存孩子的“列表”功能,那么您仍然可以為Sets模仿。

默認(rèn)情況下,集合是無(wú)序的和未排序的,但是即使您不能對(duì)它們進(jìn)行排序,也可以通過(guò)使用@OrderBy JPA注釋按給定的列對(duì)它們進(jìn)行排序,如下所示:

@Entity public class LinkedParent {...@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", orphanRemoval = true) @OrderBy("id") private Set children = new LinkedHashSet();...public Set getChildren() { return children; }public void addChild(LinkedChild child) { children.add(child); child.setParent(this); }public void removeChild(LinkedChild child) { children.remove(child); child.setParent(null); } }

加載父級(jí)的子級(jí)時(shí),生成SQL類(lèi)似于:

select children0_.parent_id as parent_i3_3_1_, children0_.id as id1_2_1_, children0_.id as id1_2_0_, children0_.name as name2_2_0_, children0_.parent_id as parent_i3_2_0_ from LinkedChild children0_ where children0_.parent_id=? order by children0_.id

結(jié)論:

如果您的領(lǐng)域模型要求使用列表而不是集合,則將打破您的約束,不允許重復(fù)。 但是,如果您需要重復(fù)項(xiàng),則仍然可以使用索引列表。 據(jù)說(shuō)Bag是未排序且“無(wú)序的”(即使它按照在數(shù)據(jù)庫(kù)表中添加子的順序來(lái)檢索子)。 因此,索引列表也將是一個(gè)不錯(cuò)的選擇,對(duì)嗎?

我還想提請(qǐng)注意一個(gè)5年的bug,它影響了多個(gè)Hibernate版本,并且是我在多個(gè)項(xiàng)目中復(fù)制的一個(gè)版本。 當(dāng)然,有一些解決方法,例如刪除Cascade.Merge或合并Children vs the Parent,但是有許多開(kāi)發(fā)人員不知道此問(wèn)題及其解決方法。

根據(jù)Hibernate docs:集是“ 表示多值關(guān)聯(lián)的推薦方法 ”,而且我已經(jīng)看到很多情況下使用Bags作為默認(rèn)雙向集合,即使無(wú)論如何集都是更好的選擇。

因此,我仍然對(duì)Bags保持謹(jǐn)慎,如果我的領(lǐng)域模型強(qiáng)加使用List,我總是會(huì)選擇索引的。

  • 代碼可在GitHub上獲得 。

參考: Hibernate Facts:來(lái)自Vlad Mihalcea博客博客的JCG合作伙伴 Vlad Mihalcea偏愛(ài)雙向集合與列表 。

翻譯自: https://www.javacodegeeks.com/2013/10/hibernate-facts-favoring-bidirectional-sets-vs-lists.html

總結(jié)

以上是生活随笔為你收集整理的Hibernate事实:有利于双向集vs列表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。