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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

hibernate语句_如何优化Hibernate EllementCollection语句

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hibernate语句_如何优化Hibernate EllementCollection语句 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

hibernate語句

介紹

Hibernate支持三種數據映射類型 : 基本 (例如String,int), Embeddable和Entity 。 通常,數據庫行被映射到Entity ,每個數據庫列都與一個基本屬性相關聯。 當將多個字段映射組合到一個可重用的組中時, 可嵌入的類型更為常見( Embeddable被合并到擁有的實體映射結構中)。

這兩種基本類型和Embeddables可以通過被關聯到一個實體 @ElementCollection ,在一實體-許多類非實體關系。

測試時間

對于即將到來的測試用例,我們將使用以下實體模型:

修補程序具有變更可嵌入對象的集合。

@ElementCollection @CollectionTable(name="patch_change",joinColumns=@JoinColumn(name="patch_id") ) private List<Change> changes = new ArrayList<>();

Change對象建模為Embeddable類型,并且只能通過其所有者Entity進行訪問。 Embeddable沒有標識符 ,因此無法通過JPQL查詢。 Embeddable生命周期綁定到其所有者的生命周期,因此任何實體狀態轉換都會自動傳播到Embeddable集合。

首先,我們需要添加一些測試數據:

doInTransaction(session -> {Patch patch = new Patch();patch.getChanges().add(new Change("README.txt", "0a1,5..."));patch.getChanges().add(new Change("web.xml", "17c17..."));session.persist(patch); });

添加一個新元素

讓我們看看將新的Change添加到現有Patch時會發生什么:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().add(new Change("web.xml", "1d17...")); });

此測試生成以下SQL輸出:

DELETE FROM patch_change WHERE patch_id = 1INSERT INTO patch_change (patch_id, diff, path) VALUES (1, '0a1,5...', 'README.txt') INSERT INTO patch_change(patch_id, diff, path) VALUES (1, '17c17...', 'web.xml') INSERT INTO patch_change(patch_id, diff, path) VALUES (1, '1d17...', 'web.xml')

默認情況下,任何收集操作最終都會重新創建整個數據集。 這種行為僅對于內存中的集合是可接受的,并且從數據庫的角度來看是不合適的。 數據庫必須刪除所有現有的行,而只是重新添加它們的后綴。 我們在該表上擁有的索引越多,性能損失就越大。

刪除元素

刪除元素沒有什么不同:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().remove(0); });

此測試用例生成以下SQL語句:

DELETE FROM patch_change WHERE patch_id = 1INSERT INTO patch_change(patch_id, diff, path) VALUES (1, '17c17...', 'web.xml')

刪除了所有表行,并將剩余的內存中條目刷新到數據庫中。

Java Persistence Wiki Book清楚地記錄了這種行為:

JPA 2.0規范沒有提供在Embeddable中定義ID的方法。 但是,要刪除或更新ElementCollection映射的元素,通常需要一些唯一鍵。 否則,在每次更新時,JPA提供程序都將需要從實體的CollectionTable中刪除所有內容,然后再將值插入回去。 因此,JPA提供程序很可能會假定Embeddable中所有字段的組合與外鍵(JoinColumn(s))組合在一起都是唯一的。 但是,如果Embeddable很大或很復雜,這可能效率很低,或者根本不可行。

一些JPA提供程序可能允許在可嵌入對象中指定ID,以解決此問題。 請注意,在這種情況下,對于集合,該ID僅需是唯一的,而不是該表,因為其中包括外鍵。 有些可能還允許將CollectionTable上的唯一選項用于此目的。 否則,如果您的Embeddable很復雜,則可以考慮將其設為實體,而改用OneToMany。

添加一個OrderColumn

為了優化ElementCollection行為,我們需要應用適用于一對多關聯的相同技術。 元素的收集就像是單向的一對多關系,并且我們已經知道idbag的 性能比單向bag更好 。

因為可嵌入對象不能包含標識符,所以我們至少可以添加一個訂單列,以便可以唯一地標識每一行。 讓我們看看將@OrderColumn添加到元素集合時會發生什么:

@ElementCollection @CollectionTable(name="patch_change",joinColumns=@JoinColumn(name="patch_id") ) @OrderColumn(name = "index_id") private List<Change> changes = new ArrayList<>();

刪除實體后,以前的測試結果沒有任何改善:

DELETE FROM patch_change WHERE patch_id = 1INSERT INTO patch_change(patch_id, diff, path) VALUES (1, '17c17...', 'web.xml')

這是因為在阻止重新創建集合時, AbstractPersistentCollection將檢查可為空的列:

@Override public boolean needsRecreate(CollectionPersister persister) {if (persister.getElementType() instanceof ComponentType) {ComponentType componentType = (ComponentType) persister.getElementType();return !componentType.hasNotNullProperty();}return false; }

現在,我們將添加NOT NULL約束并重新運行測試:

@Column(name = "path", nullable = false) private String path;@Column(name = "diff", nullable = false) private String diff;

添加一個新的有序元素

將元素添加到列表的末尾將生成以下語句:

INSERT INTO patch_change(patch_id, index_id, diff, path) VALUES (1, 2, '1d17...', 'web.xml')

index_id列用于持久存儲內存中的收集順序。 添加到集合的末尾不會影響現有元素的順序,因此僅需要一個INSERT語句。

添加一個新的第一個元素

如果我們在列表的開頭添加一個新元素:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().add(0, new Change("web.xml", "1d17...")); });

生成以下SQL輸出:

UPDATE patch_change SET diff = '1d17...',path = 'web.xml' WHERE patch_id = 1AND index_id = 0 UPDATE patch_change SET diff = '0a1,5...',path = 'README.txt' WHERE patch_id = 1AND index_id = 1INSERT INTO patch_change (patch_id, index_id, diff, path) VALUES (1, 2, '17c17...', 'web.xml')

現有數據庫條目已更新,以反映新的內存中數據結構。 由于新添加的元素已添加到列表的開頭,因此它將觸發對表的第一行的更新。 所有INSERT語句在列表的末尾發出,并且所有現有元素均根據新的列表順序進行更新。

@OrderColumn Java持久性文檔中對此行為進行了說明:

當更新關聯或元素集合時,持久性提供程序維護order列的值的連續(非稀疏)排序。 第一個元素的訂單列值為0。

刪除有序元素

如果我們刪除最后一個條目:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().remove(patch.getChanges().size() - 1); });

僅發出一個DELETE語句:

DELETE FROM patch_change WHERE patch_id = 1AND index_id = 1

刪除第一個元素條目

如果刪除第一個元素,則會執行以下語句:

DELETE FROM patch_change WHERE patch_id = 1AND index_id = 1 UPDATE patch_change SET diff = '17c17...',path = 'web.xml' WHERE patch_id = 1AND index_id = 0

Hibernate刪除所有多余的行,然后更新其余的行。

從中間刪除

如果我們從列表中間刪除一個元素:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().add(new Change("web.xml", "1d17..."));patch.getChanges().add(new Change("server.xml", "3a5...")); });doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().remove(1); });

執行以下語句:

DELETE FROM patch_change WHERE patch_id = 1AND index_id = 3UPDATE patch_change SET diff = '1d17...',path = 'web.xml' WHERE patch_id = 1AND index_id = 1 UPDATE patch_change SET diff = '3a5...',path = 'server.xml' WHERE patch_id = 1AND index_id = 2

有序ElementCollection的更新如下:

  • 調整數據庫表的大小,使用DELETE語句刪除表末尾的多余行。 如果內存中的集合大于數據庫中的集合,則所有INSERT語句將在列表的末尾執行
  • 添加/刪除條目之前的所有元素均保持不變
  • 添加/刪除元素之后的其余元素將更新以匹配新的內存中收集狀態

結論

與一對多 反向關聯相比, ElementCollection更難優化。 如果集合經常更新,則元素集合最好用一對多關聯替換。 當我們不想為表示外鍵端而添加額外的實體時,元素集合更適合于很少更改的數據。

  • 代碼可在GitHub上獲得 。

翻譯自: https://www.javacodegeeks.com/2015/05/how-to-optimize-hibernate-ellementcollection-statements.html

hibernate語句

總結

以上是生活随笔為你收集整理的hibernate语句_如何优化Hibernate EllementCollection语句的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。