再談Hibernate級聯(lián)刪除——JPA下的Hibernate實現(xiàn)一對多級聯(lián)刪除Casca...
聲明:
1、本文系原創(chuàng),非抄襲或轉(zhuǎn)載過來的。
2、本文論點都親手做過實驗論證。
3、本文所講的Hibernate配置都基于注解的方式,hbm語法未提供。
很多人對持久層概念搞不清JPA、Hibernate、EJB3.0的關(guān)系,這里做一下簡單的說明:JPA是一個持久層設(shè)計接口,EJB3.0和Hibernate是具體的實現(xiàn)類,EJB3.0和Hibernate的功能近似相等的(Hibernate沒有Session Bean,Spring MVC3的SessionAttribute跟Session Bean近似)。
理論是使用JPA接口可以無縫切換持久層實現(xiàn),但是僅僅是理論上?。?!
JPA是在Hibernate成熟并大行其道的時候才推出的,基本上是借鑒Hibernate的優(yōu)點,做了一個統(tǒng)一的標(biāo)準(zhǔn)而已,JPA1.0沒有一對多的級聯(lián)刪除配置,也許JPA2.0里才有吧(這里沒做過調(diào)研)
@OneToMany(mappedBy = "commentTeam")
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE,org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
private Set<CommentTeamMember> commentTeamMembers;
這里為了說明,只貼出一對多的關(guān)鍵代碼,其它無關(guān)的注解已忽略掉,以免造成干擾。
這里重點說明一下四個常用的注解配置的區(qū)別:
CascadeType.SAVE_UPDATE
CascadeType.ALL
CascadeType.DELETE
CascadeType.DELETE_ORPHAN
之所有之列出這四個,是因為我不想跟書本上把所有的概念都羅列出來?;旧祥_發(fā)時其中的3個都以及足夠用了,下面我結(jié)合代碼演示一下他們之間的區(qū)別,以及使用的時候注意的地方。
CascadeType.SAVE_UPDATE:Hibernate專有的,JPA并不支持,作用是級聯(lián)保存、級聯(lián)更新(注:JPA很惡心,要么你配置
CascadeType.ALL,要么你配CascadeType.SAVE+CasadeType.Merge。八卦一句:專家雖牛,多年不寫代碼,定的標(biāo)準(zhǔn)讓編碼麻煩呀?。?br>CascadeType.ALL:級聯(lián)保存、修改、刪除、同步,一般很少用,看看控制臺的一長串SQL就知道性能低下,你沒改的關(guān)聯(lián)表也給你發(fā)update語句,我從來沒用過這個屬性。
CascadeType.DELETE:當(dāng)調(diào)用session.delete(A)的時候,級聯(lián)刪除關(guān)聯(lián)的對象。(注:先調(diào)用A.setB(null),再調(diào)用session.delete(A),這樣是級聯(lián)刪不掉B的。
CascadeType.DELETE_ORPHAN:一對多級聯(lián)刪除。
下面重點來說說這個CascadeType.DELETE_ORPHAN:
看過API、開發(fā)指南,級聯(lián)刪除就一個經(jīng)典的
@OneToMany(mappedBy = "commentTeam")
@Cascade({CascadeType.SAVE_UPDATE,CascadeType.DELETE_ORPHAN})
private Set<CommentTeamMember> commentTeamMembers;
mappedBy不可少,映射A->B一對多的另一邊控制反轉(zhuǎn)(誰控誰的問題),新版的Hibernate3.4中配置更簡單,變一句了,更簡潔吧?
@OneToMany(mappedBy = "commentTeam",orphanRemoval=true)
private Set<CommentTeamMember> commentTeamMembers;
以上兩種配置方式是等價的,下面是在實際開發(fā)中的使用了,有些時候代碼方面不注意,會誤以為明明配置正確了,但為什么不起作用呢? 下面例舉一下代碼,請看Action代碼(實際上我在Spring Controller里,N年不寫DAO了,Service很少用,Manager一邊去!)
CommentTeam commentTeam=this.getHibernateTemplate.get(CommentTeam.class,id);
commentTeam.setCommentTeamMember(null);//想級聯(lián)刪除子表數(shù)據(jù)
this.getHibernateTemplate.saveOrUpdate(commentTeam);
這樣級聯(lián)刪除卻沒有發(fā)生?為什么呢?
再來一個例子
CommentTeam commentTeam=this.getHibernateTemplate.get(CommentTeam.class,id);
Set<CommentTeamMember> commentTeamMembers=new HashSet<CommentTeamMember>();
commentTeam.setCommentTeamMember(commentTeamMembers);//想級聯(lián)刪除子表數(shù)據(jù)或增減替換對象
this.getHibernateTemplate.saveOrUpdate(commentTeam);
這個例子級聯(lián)刪除的效果也沒發(fā)生!即使commentTeamMembers理由有若干個對象。
成功執(zhí)行級聯(lián)刪除的語法:
CommentTeam commentTeam=this.getHibernateTemplate.get(CommentTeam.class,id);
commentTeam.getCommentTeamMember().clear();//注意這里引用的集合還是原理的集合,這里沒有重新new過
commentTeam.getCommentTeamMember().add(new CommentTeamMember());//如果想替換為新的集合可以用addAll方法
this.getHibernateTemplate.saveOrUpdate(commentTeam);
分析一下原因:級聯(lián)刪除起作用的前提是關(guān)聯(lián)的集合對象不能重新指向新的引用,必須在原有的集合里操作新增、刪除、清空元素,像上面的setXXX(null)的方法等是起步到級聯(lián)刪除作用的,大概是Hibernate自認(rèn)自己原生的集合對象吧,自己New的放進(jìn)行級聯(lián)刪除無效!
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。