jpa和hibernate_使用JPA和Hibernate有效删除数据
jpa和hibernate
您可能會遇到必須對關系數據庫中存儲的大量數據集執行批量刪除的情況。 如果您將JPA與Hibernate一起用作基礎OR映射器,則可以嘗試通過以下方式調用EntityManager的remove()方法:
首先,我們加載要刪除的實體的引用表示形式,然后將此引用傳遞給EntityManager。 假設上面的RootEntity與名為ChildEntity的類有子關系:
@OneToMany(mappedBy = "rootEntity", fetch = FetchType.EAGER, cascade = CascadeType.ALL) private Set childEntities = new HashSet(0);如果現在打開hibernate的屬性show_sql,我們將想知道發出什么SQL語句:
selectrootentity0_.id as id5_1_,rootentity0_.field1 as field2_5_1_,rootentity0_.field2 as field3_5_1_,childentit1_.PARENT as PARENT5_3_,childentit1_.id as id3_,childentit1_.id as id4_0_,childentit1_.field1 as field2_4_0_,childentit1_.field2 as field3_4_0_,childentit1_.PARENT as PARENT4_0_fromROOT_ENTITY rootentity0_left outer joinCHILD_ENTITY childentit1_on rootentity0_.id=childentit1_.PARENTwhererootentity0_.id=?deletefromCHILD_ENTITYwhereid=?deletefromROOT_ENTITYwhereid=?為什么Hibernate首先將所有數據加載到內存中以便隨后立即刪除該數據? 原因是JPA的生命周期要求對象處于“托管”狀態,然后才能刪除它。 僅在這種狀態下,所有生命周期功能(如攔截器)才可用(請參閱此處 )。 因此,Hibernate在刪除之前發出SELECT查詢,以便將RootEntity和ChildEntity都轉移到“托管”狀態。 但是,如果我們只想刪除RootEntity和ChildEntity,并且知道RootEntity的ID,該怎么辦? 答案是使用類似于以下內容的簡單DELETE查詢。 但是由于子表的完整性約束,我們首先必須刪除所有依賴的子實體。 以下代碼演示了如何:
List childIds = entityManager.createQuery("select c.id from ChildEntity c where c.rootEntity.id = :pid").setParameter("pid", id).getResultList(); for(Long childId : childIds) {entityManager.createQuery("delete from ChildEntity c where c.id = :id").setParameter("id", childId).executeUpdate(); } entityManager.createQuery("delete from RootEntity r where r.id = :id").setParameter("id", id).executeUpdate();上面的代碼通過調用remove()產生了我們期望的三個SQL語句。 現在您可能會說,這種刪除方式比僅調用EntityManager的remove()方法更為復雜。 它還會忽略我們在兩個實體類中放置的注釋,例如@OneToMany和@ManyToOne。 那么,為什么不編寫一些代碼來使用關于兩個類文件中已經存在的兩個實體的知識呢? 首先,我們在RootEntity類中使用反射查找@OneToMany批注,提取子實體的類型,然后查找其后向字段,并用@ManyToOne批注。 完成此操作后,我們可以以更通用的方式輕松編寫三個SQL語句:
public void delete(EntityManager entityManager, Class parentClass, Object parentId) {Field idField = getIdField(parentClass);if (idField != null) {List oneToManyFields = getOneToManyFields(parentClass);for (Field field : oneToManyFields) {Class childClass = getFirstActualTypeArgument(field);if (childClass != null) {Field manyToOneField = getManyToOneField(childClass, parentClass);Field childClassIdField = getIdField(childClass);if (manyToOneField != null && childClassIdField != null) {List childIds = entityManager.createQuery(String.format("select c.%s from %s c where c.%s.%s = :pid", childClassIdField.getName(), childClass.getSimpleName(), manyToOneField.getName(), idField.getName())).setParameter("pid", parentId).getResultList();for (Long childId : childIds) {entityManager.createQuery(String.format("delete from %s c where c.%s = :id", childClass.getSimpleName(), childClassIdField.getName())).setParameter("id", childId).executeUpdate();}}}}entityManager.createQuery(String.format("delete from %s e where e.%s = :id", parentClass.getSimpleName(), idField.getName())).setParameter("id", parentId).executeUpdate();} }上面的代碼中的方法getFirstActualTypeArgument(),getManyToOneField(),getIdField()和getOneToManyFields()并未在此處顯示,但是聽起來像它們的名字。 實施后,我們可以輕松刪除所有以樹的根開頭的實體。
- 可以在github上找到一個可用于檢查上述行為和解決方案的簡單示例應用程序。
翻譯自: https://www.javacodegeeks.com/2013/11/efficiently-delete-data-with-jpa-and-hibernate.html
jpa和hibernate
總結
以上是生活随笔為你收集整理的jpa和hibernate_使用JPA和Hibernate有效删除数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 鬼子姜的禁忌 鬼子姜的禁忌有哪些
- 下一篇: 身体是革命的本钱什么意思 身体是革命的本