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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

如何使用Hibernate批处理DELETE语句

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

介紹

在我以前的文章中 ,我解釋了批處理INSERT和UPDATE語句所需的Hibernate配置。 這篇文章將繼續本主題的DELETE語句批處理。

領域模型實體

我們將從以下實體模型開始:

Post實體與Comment具有一對多關聯,并且與PostDetails實體具有一對一關系:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "post",orphanRemoval = true) private List<Comment> comments = new ArrayList<>();@OneToOne(cascade = CascadeType.ALL, mappedBy = "post",orphanRemoval = true, fetch = FetchType.LAZY) private PostDetails details;

即將進行的測試將針對以下數據進行:

doInTransaction(session -> {int batchSize = batchSize();for(int i = 0; i < itemsCount(); i++) {int j = 0;Post post = new Post(String.format("Post no. %d", i)); post.addComment(new Comment( String.format("Post comment %d:%d", i, j++)));post.addComment(new Comment(String.format("Post comment %d:%d", i, j++)));post.addDetails(new PostDetails());session.persist(post);if(i % batchSize == 0 && i > 0) {session.flush();session.clear();}} });

休眠配置

正如已經說明 ,以下屬性所需的配料INSERT和UPDATE語句:

properties.put("hibernate.jdbc.batch_size", String.valueOf(batchSize())); properties.put("hibernate.order_inserts", "true"); properties.put("hibernate.order_updates", "true"); properties.put("hibernate.jdbc.batch_versioned_data", "true");

接下來,我們將檢查DELETE語句是否也被批處理。

JPA級聯刪除

因為級聯實體狀態轉換很方便,所以我將證明CascadeType.DELETE和JDBC批處理不能很好地混合使用。

以下測試將要進行:

  • 選擇一些帖子以及評論和帖子 詳細信息
  • 刪除帖子 ,同時將delete事件傳播到Comments和PostDetails
@Test public void testCascadeDelete() {LOGGER.info("Test batch delete with cascade");final AtomicReference<Long> startNanos = new AtomicReference<>();addDeleteBatchingRows();doInTransaction(session -> {List<Post> posts = session.createQuery("select distinct p " +"from Post p " +"join fetch p.details d " +"join fetch p.comments c").list();startNanos.set(System.nanoTime());for (Post post : posts) {session.delete(post);}});LOGGER.info("{}.testCascadeDelete took {} millis",getClass().getSimpleName(),TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos.get())); }

運行此測試將給出以下輸出:

Query:{[delete from Comment where id=? and version=?][55,0]} {[delete from Comment where id=? and version=?][56,0]} Query:{[delete from PostDetails where id=?][3]} Query:{[delete from Post where id=? and version=?][3,0]} Query:{[delete from Comment where id=? and version=?][54,0]} {[delete from Comment where id=? and version=?][53,0]} Query:{[delete from PostDetails where id=?][2]} Query:{[delete from Post where id=? and version=?][2,0]} Query:{[delete from Comment where id=? and version=?][52,0]} {[delete from Comment where id=? and version=?][51,0]} Query:{[delete from PostDetails where id=?][1]} Query:{[delete from Post where id=? and version=?][1,0]}

僅批注Comment DELETE語句,其他實體在單獨的數據庫往返中刪除。

此行為的原因由ActionQueue排序實現給出:

if ( session.getFactory().getSettings().isOrderUpdatesEnabled() ) {// sort the updates by pkupdates.sort(); } if ( session.getFactory().getSettings().isOrderInsertsEnabled() ) {insertions.sort(); }

雖然介紹了INSERTS和UPDATES ,但根本不對DELETE語句進行排序。 僅當所有語句都屬于同一數據庫表時,才能重新使用JDBC批處理。 當傳入語句針對另一個數據庫表時,必須釋放當前批處理,以便新批處理與當前語句數據庫表匹配:

public Batch getBatch(BatchKey key) {if ( currentBatch != null ) {if ( currentBatch.getKey().equals( key ) ) {return currentBatch;}else {currentBatch.execute();currentBatch.release();}}currentBatch = batchBuilder().buildBatch(key, this);return currentBatch; }

移除孤兒和手動沖洗

一種變通方法是在前進到新的Child關聯之前,先手動刷新Hibernate Session,然后解除所有Child實體的關聯:

@Test public void testOrphanRemoval() {LOGGER.info("Test batch delete with orphan removal");final AtomicReference<Long> startNanos = new AtomicReference<>();addDeleteBatchingRows();doInTransaction(session -> {List<Post> posts = session.createQuery("select distinct p " +"from Post p " +"join fetch p.details d " +"join fetch p.comments c").list();startNanos.set(System.nanoTime());posts.forEach(Post::removeDetails);session.flush();posts.forEach(post -> {for (Iterator<Comment> commentIterator = post.getComments().iterator(); commentIterator.hasNext(); ) {Comment comment = commentIterator.next();comment.post = null;commentIterator.remove();}});session.flush();posts.forEach(session::delete);});LOGGER.info("{}.testOrphanRemoval took {} millis",getClass().getSimpleName(),TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos.get())); }

這次,所有DELETE語句均已正確批處理:

Query:{[delete from PostDetails where id=?][2]} {[delete from PostDetails where id=?][3]} {[delete from PostDetails where id=?][1]} Query:{[delete from Comment where id=? and version=?][53,0]} {[delete from Comment where id=? and version=?][54,0]} {[delete from Comment where id=? and version=?][56,0]} {[delete from Comment where id=? and version=?][55,0]} {[delete from Comment where id=? and version=?][52,0]} {[delete from Comment where id=? and version=?][51, Query:{[delete from Post where id=? and version=?][2,0]} {[delete from Post where id=? and version=?][3,0]} {[delete from Post where id=? and version=?][1,0]}

SQL級聯刪除

更好的解決方案是使用SQL級聯刪除,而不是JPA實體狀態傳播機制。 這樣,我們還可以減少DML語句的數量。 由于Hibernate Session充當事務后寫式緩存 ,因此在將實體狀態轉換與數據庫端自動操作混合使用時,我們必須格外謹慎,因為持久性上下文可能無法反映最新的數據庫更改。

Post實體一對多 注釋關聯使用Hibernate特定的@OnDelete批注進行標記,以便自動生成的數據庫模式包括ON DELETE CASCADE指令:

@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "post") @OnDelete(action = OnDeleteAction.CASCADE) private List<Comment> comments = new ArrayList<>();

生成以下DDL :

alter table Comment add constraint FK_apirq8ka64iidc18f3k6x5tc5 foreign key (post_id) references Post on delete cascade

使用PostDetails實體一對一的Post關聯也可以做到這一點 :

@OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "id") @MapsId @OnDelete(action = OnDeleteAction.CASCADE) private Post post;

以及相關的DDL :

alter table PostDetails add constraint FK_h14un5v94coafqonc6medfpv8 foreign key (id) references Post on delete cascade

CascadeType.ALL和orphanRemoval替換為CascadeType.PERSIST和CascadeType.MERGE ,因為我們不再希望Hibernate傳播實體刪除事件。

測試僅刪除Post實體。

doInTransaction(session -> {List<Post> posts = session.createQuery("select p from Post p").list();startNanos.set(System.nanoTime());for (Post post : posts) {session.delete(post);} });

由于只有一個目標表,因此DELETE語句已正確批處理。

Query:{[delete from Post where id=? and version=?][1,0]} {[delete from Post where id=? and version=?][2,0]} {[delete from Post where id=? and version=?][3,0]}

結論

如果INSERT和UPDATE語句的批處理只是配置問題,則DELETE語句需要一些其他步驟,這可能會增加數據訪問層的復雜性。

  • 代碼可在GitHub上獲得 。

翻譯自: https://www.javacodegeeks.com/2015/03/how-to-batch-delete-statements-with-hibernate.html

總結

以上是生活随笔為你收集整理的如何使用Hibernate批处理DELETE语句的全部內容,希望文章能夠幫你解決所遇到的問題。

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