电竞比分网-中国电竞赛事及体育赛事平台

分享

Hibernate與數(shù)據(jù)庫觸發(fā)器協(xié)同工作

 feimishiwo 2014-04-29
 
                                 Hibernate與數(shù)據(jù)庫觸發(fā)器協(xié)同工作
  數(shù)據(jù)庫觸發(fā)器是數(shù)據(jù)庫的一種監(jiān)聽機(jī)制,這種機(jī)制會(huì)監(jiān)視數(shù)據(jù)庫中的某種特定的操作,當(dāng)這種操作發(fā)生時(shí),觸發(fā)器就會(huì)執(zhí)行,并且會(huì)完成一些特定的邏輯,在數(shù)據(jù)庫中能夠激發(fā)觸發(fā)器的操作有:insert,update,delete三種,當(dāng)這三種操作發(fā)生在一條記錄或者某個(gè)特殊字段上,如果在該記錄或者該字段上有觸發(fā)器,那么觸發(fā)器便會(huì)被激發(fā)執(zhí)行。但是當(dāng)Hibernate與觸發(fā)器協(xié)同執(zhí)行時(shí),會(huì)造成兩個(gè)問題。
第一:觸發(fā)器使得Session中的數(shù)據(jù)與數(shù)據(jù)庫中的數(shù)據(jù)不一致;
第二:Sessionupdate操作會(huì)盲目觸發(fā)觸發(fā)器;
下面我們就分別討論這兩個(gè)問題的原因和解決辦法。
A、觸發(fā)器使得Session中的數(shù)據(jù)與數(shù)據(jù)庫中的數(shù)據(jù)不一致:
造成這個(gè)問題的根本原因,是因?yàn)橛|發(fā)器對(duì)數(shù)據(jù)庫的操作對(duì)Hibernate Session是透明的,觸發(fā)器對(duì)數(shù)據(jù)庫的某些更改,無法被Session感知,因此無法被同步到緩存之中,我們看下面的代碼,假設(shè)在數(shù)庫中的user表中的registerd_time字段上設(shè)置了一個(gè)觸發(fā)器,當(dāng)有新的user對(duì)象被保存時(shí),數(shù)據(jù)庫就自動(dòng)將數(shù)據(jù)庫當(dāng)前時(shí)間之值,插入到該字段中:
tx=session.beginTransaction();
session.save(user);
System.out.println(user.getRegisterdTime());
tx.commit();
當(dāng)執(zhí)行完save()操作后,打印注冊(cè)時(shí)間字段,這時(shí)發(fā)現(xiàn)該字段值為空。這是因?yàn)榇藭r(shí)真正的insert SQL語句還沒有真正執(zhí)行,所以觸發(fā)器還沒有被執(zhí)行。我們修改上面的代碼如下:
tx=session.beginTransaction();
session.save(user);
session.flush();
System.out.println(user.getRegisterdTime());
user=session.load(User.class,”1”);
System.out.println(user.getRegisterdTime());
tx.commit();
我們?cè)黾恿藦?qiáng)制清空緩存并且強(qiáng)制提交的操作,這個(gè)操作會(huì)激發(fā)insert SQL語句的執(zhí)行,并且激發(fā)觸發(fā)器的執(zhí)行,此時(shí)打印注冊(cè)時(shí)間發(fā)現(xiàn)已經(jīng)變成了數(shù)據(jù)庫當(dāng)前時(shí)間,但是當(dāng)再次加載剛剛被保存的user對(duì)象后打印注冊(cè)時(shí)間,發(fā)現(xiàn)還是空值,這是因?yàn)橛捎谟|發(fā)器會(huì)自動(dòng)填寫注冊(cè)時(shí)間值,所以在構(gòu)造user對(duì)象時(shí)沒有設(shè)置該屬性值,這個(gè)屬性值被觸發(fā)器在數(shù)據(jù)庫端自動(dòng)設(shè)置,但是由于觸發(fā)器對(duì)數(shù)據(jù)庫的操作對(duì)Hibernate Session是透明的,觸發(fā)器對(duì)該字段的更改,無法被Session感知,所以在緩存中該字段仍然是null,當(dāng)加載這個(gè)對(duì)象時(shí),由于save操作此對(duì)象被置于緩存中,所以load方法從緩存中將該對(duì)象獲得,當(dāng)調(diào)用user.getRegisterdTime()時(shí)會(huì)得到緩存中的空值。那么我們?cè)鯓硬拍鼙苊獬霈F(xiàn)這個(gè)問題呢?看下面的代碼:
tx=session.beginTransaction();
session.save(user);
session.flush();
System.out.println(user.getRegisterdTime());
session.refresh(user);
user=session.load(User.class,”1”);
System.out.println(user.getRegisterdTime());
tx.commit();
這里我們調(diào)用了refresh方法,該方法會(huì)重新從數(shù)據(jù)庫中加載剛剛被保存的user對(duì)象到緩存中,這樣就同步了緩存與數(shù)據(jù)庫數(shù)據(jù),所以當(dāng)再次調(diào)用load方法時(shí),從緩存中獲得的數(shù)據(jù)就會(huì)同數(shù)據(jù)庫中的數(shù)據(jù)保持同步,所以再次打印注冊(cè)時(shí)間時(shí),就會(huì)打印出數(shù)據(jù)庫當(dāng)前時(shí)間。
B、Sessionupdate操作會(huì)盲目觸發(fā)觸發(fā)器:
如果在數(shù)據(jù)庫中定義了針對(duì)update操作的觸發(fā)器,那么必須要謹(jǐn)慎的使用SessionupdatesaveOrUpdate(),因?yàn)檫@兩個(gè)方法能夠使一個(gè)游離對(duì)象再次變成持久化對(duì)象,因?yàn)橛锌赡茉?/span>Session的緩存中,還不存在要更新對(duì)象的快照,所以就無法判斷游離對(duì)象的屬性是否與數(shù)據(jù)庫中保持一致,為了保險(xiǎn)起見,Hibernate默認(rèn)的操作是,不管實(shí)體對(duì)象的屬性是否發(fā)生了變化,都要發(fā)起一條update SQL語句的執(zhí)行,來同步實(shí)體對(duì)象屬性值與數(shù)據(jù)庫字段值,即同步數(shù)據(jù)庫字段值與緩存數(shù)據(jù)屬性值。這時(shí)如果對(duì)應(yīng)的數(shù)據(jù)庫表中有update觸發(fā)器,那么就會(huì)觸發(fā)該觸發(fā)器的執(zhí)行,但是如果此時(shí)這個(gè)對(duì)象的屬性值并沒有發(fā)生改變,也就是說實(shí)體對(duì)象的屬性值與數(shù)據(jù)庫中對(duì)應(yīng)表的對(duì)應(yīng)記錄保持一致,那么,這個(gè)觸發(fā)器的執(zhí)行就是沒有必要的,此時(shí)Sessionupdate操作就觸發(fā)了多余的觸發(fā)器。那么我們?cè)鯓硬拍鼙苊膺@個(gè)問題呢?我們可以開啟實(shí)體對(duì)象配置文件中<class>元素的,“select-before-update”屬性選項(xiàng),我們可以如下進(jìn)行配置:
<class name=”com.neusoft.entity.User” table=”user” select-before-update=”true”>
 
   ……
 
</class>
這時(shí)當(dāng)執(zhí)行Session.update()/saveOrUpdate()操作時(shí),會(huì)首先執(zhí)行select SQL,查詢出該對(duì)象所有
屬性值,然后與要進(jìn)行更新的實(shí)體對(duì)象屬性值進(jìn)行比較,如果都相同,那么就不會(huì)執(zhí)行update
作,這時(shí)就不會(huì)由于執(zhí)行了沒必要的update SQL語句,而激發(fā)多余的update觸發(fā)器操作了。
 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多