欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

HibernateTemplate中HibernateCallback的事務(wù)

系統(tǒng) 2221 0

HibernateTemplate中HibernateCallback的事務(wù)

目的:使用HibernateTemplate執(zhí)行execute(new HibernateCallback())方法,從HibernateCallback中得到session,在此session中做多個操作,并希望這些操作位于同一個事務(wù)中。
??????如果你這樣寫(1):
??????
public ? static ? void ?main(String?ss[])? {
????????CtxUtil.getBaseManager().getHibernateTemplate().execute(
new ?HibernateCallback()? {
????????????
public ?Object?doInHibernate(Session?session)? throws ?HibernateException,?SQLException? {
????????????????
// ?保存stu1
????????????????Student?stu1? = ? new ?Student();
????????????????stu1.setName(
" aaaa " ); // ?在數(shù)據(jù)庫中,name字段不允許為null
????????????????session.save(stu1);
????????????????session.flush();//實際上,如果不是程序員"手癢"來調(diào)用這個flush(),HibernateTemplate中session的事務(wù)處理還是很方便的

????????????????Student?stu2?
= ? new ?Student();
????????????????session.save(stu2);
// ?沒有設(shè)置name字段,預(yù)期會報出例外
????????????????session.flush();
????????????????
return ? null ;
????????????}

????????}
);

????}
????? 你期望spring在執(zhí)行完execute回調(diào)后,在關(guān)閉session的時候提交事務(wù),想法是很好的,但spring并不會這么做.讓我們來看看在Hibernate的源代碼中,session.beginTransation()做了什么事。看如下代碼(2):
public ?Transaction?beginTransaction()? throws ?HibernateException? {
????????errorIfClosed();
????????
if ?(?rootSession? != ? null ?)? {
????????????
// ?todo?:?should?seriously?consider?not?allowing?a?txn?to?begin?from?a?child?session
????????????
// ??????can?always?route?the?request?to?the?root?session
????????????log.warn(? " Transaction?started?on?non-root?session " ?);
????????}

????????Transaction?result?
= ?getTransaction();
????????result.begin();
????????
return ?result;
????}
這個方法中的result是一個org.hibernate.transaction.JDBCTransaction實例,而方法中的getTransaction()方法源代碼為(3):
public ?Transaction?getTransaction()? throws ?HibernateException? {
????????
if ?(hibernateTransaction == null )? {
????????????log.error(owner.getFactory().getSettings()
????????????????????.getTransactionFactory().getClass());
????????????hibernateTransaction?
= ?owner.getFactory().getSettings()
????????????????????.getTransactionFactory()
????????????????????.createTransaction(?
this ,?owner?);
????????}

????????
return ?hibernateTransaction;
????}
再次追蹤,owner.getFactory().getSettings()?.getTransactionFactory()的createTransaction()方法源代碼如下(4):
public ?Transaction?createTransaction(JDBCContext?jdbcContext,?Context?transactionContext)
????
throws ?HibernateException? {
????????
return ? new ?JDBCTransaction(?jdbcContext,?transactionContext?);
????}
它返回了一個JDBCTransaction,沒什么特別的。
在代碼2中,執(zhí)行了result.begin(),其實也就是JDBCTransaction實例的begin()方法,來看看(5):

public ? void ?begin()? throws ?HibernateException? {
????????
if ?(begun)? {
????????????
return ;
????????}

????????
if ?(commitFailed)? {
????????????
throw ? new ?TransactionException( " cannot?re-start?transaction?after?failed?commit " );
????????}

????????log.debug(
" begin " );
????????
try ? {
????????????toggleAutoCommit?
= ?jdbcContext.connection().getAutoCommit();
????????????
if ?(log.isDebugEnabled())? {
????????????????log.debug(
" current?autocommit?status:? " ? + ?toggleAutoCommit);
????????????}

????????????
if ?(toggleAutoCommit)? {
????????????????log.debug(
" disabling?autocommit " );
????????????????jdbcContext.connection().setAutoCommit(
false ); // 把自動提交設(shè)為了false
????????????}

????????}
? catch ?(SQLException?e)? {
????????????log.error(
" JDBC?begin?failed " ,?e);
????????????
throw ? new ?TransactionException( " JDBC?begin?failed:? " ,?e);
????????}

????????callback?
= ?jdbcContext.registerCallbackIfNecessary();
????????begun?
= ? true ;
????????committed?
= ? false ;
????????rolledBack?
= ? false ;

????????
if ?(timeout? > ? 0 )? {
????????????jdbcContext.getConnectionManager().getBatcher().setTransactionTimeout(timeout);
????????}


????????jdbcContext.afterTransactionBegin(
this );
????}

在直接使用Hibernate時,要在事務(wù)結(jié)束的時候,寫上一句:tx.commit(),這個commit()的源碼為:
public ? void ?commit()? throws ?HibernateException? {
????????
if ?( ! begun)? {
????????????
throw ? new ?TransactionException( " Transaction?not?successfully?started " );
????????}


????????log.debug(
" commit " );

????????
if ?( ! transactionContext.isFlushModeNever()? && ?callback)? {
????????????transactionContext.managedFlush();?
// ?if?an?exception?occurs?during
????????????
// ?flush,?user?must?call
????????????
// ?rollback()
????????}


????????notifyLocalSynchsBeforeTransactionCompletion();
????????
if ?(callback)? {
????????????jdbcContext.beforeTransactionCompletion(
this );
????????}


????????
try ? {
????????????commitAndResetAutoCommit();//重點代碼,它的作用是提交事務(wù),并把connection的autocommit屬性恢復(fù)為true
????????????log.debug(
" committed?JDBC?Connection " );
????????????committed?
= ? true ;
????????????
if ?(callback)? {
????????????????jdbcContext.afterTransactionCompletion(
true ,? this );
????????????}

????????????notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_COMMITTED);
????????}
? catch ?(SQLException?e)? {
????????????log.error(
" JDBC?commit?failed " ,?e);
????????????commitFailed?
= ? true ;
????????????
if ?(callback)? {
????????????????jdbcContext.afterTransactionCompletion(
false ,? this );
????????????}

????????????notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_UNKNOWN);
????????????
throw ? new ?TransactionException( " JDBC?commit?failed " ,?e);
????????}
? finally ? {
????????????closeIfRequired();
????????}

????}

上面代碼中,commitAndResetAutoCommit()方法的源碼如下:
private ? void ?commitAndResetAutoCommit()? throws ?SQLException? {
????????
try ? {
????????????jdbcContext.connection().commit();//這段不用說也能理解了
????????}
? finally ? {
????????????toggleAutoCommit();//這段的作用是恢復(fù)connection的autocommit屬性為true
????????}

????}

上述代碼的toggleAutoCommit()源代碼如下:
???? private ? void ?toggleAutoCommit()? {
????????
try ? {
????????????
if ?(toggleAutoCommit)? {
????????????????log.debug(
" re-enabling?autocommit " );
????????????????jdbcContext.connection().setAutoCommit(
true );//這行代碼的意義很明白了吧
????????????}

????????}
? catch ?(Exception?sqle)? {
????????????log.error(
" Could?not?toggle?autocommit " ,?sqle);
????????}

????}
????? 因此,如果你是直接使用hibernate,并手動管理它的session,并手動開啟事務(wù)關(guān)閉事務(wù)的話,完全可以保證你的事務(wù)(好像完全是廢話).
????? 但是,如果你用的是HibernateTemplate,如同源代碼1一樣,則不要指望spring在關(guān)閉session的時候為你提交事務(wù)(罪魁禍?zhǔn)拙褪窃诖a1中調(diào)用了session.flush())。因為在使用代碼1時,spring中得到session的方式如下:
Session?session? = ?(entityInterceptor? != ? null ? ? ?sessionFactory.openSession(entityInterceptor)?:?sessionFactory
????????????????.openSession());
簡單地說它就是得到了一個session,而沒有對connection的autocommit()作任何操作,spring管理范圍內(nèi)的session所持有的connection是autocommit=true的,spring借助這個屬性,在它關(guān)閉session時,提交數(shù)據(jù)庫事務(wù)。,因此如果你在源代碼1中加上一句話:
public ? static ? void ?main(String?ss[])? {
????????CtxUtil.getBaseManager().getHibernateTemplate().execute(
new ?HibernateCallback()? {
????????????
public ?Object?doInHibernate(Session?session)? throws ?HibernateException,?SQLException? {
????????????????log.info(session.connection().getAutoCommit());
// 打印一下事務(wù)提交方式
????????????????
// ?保存stu1
????????????????Student?stu1? = ? new ?Student();
????????????????stu1.setName(
" aaaa " ); // ?在數(shù)據(jù)庫中,name字段不允許為null
????????????????session.save(stu1);
????????????????session.flush();

????????????????Student?stu2?
= ? new ?Student();
????????????????session.save(stu2);
// ?沒有設(shè)置name字段,預(yù)期會報出例外
????????????????session.flush();
????????????????
return ? null ;
????????????}

????????}
);

????}
???? 運(yùn)行后,它打出的結(jié)果是true,也就是說,雖然保存stu2時會報出例外,但如果commit屬性為true,則每一個到達(dá)數(shù)據(jù)庫的sql語句會立即被提交。換句話說,在調(diào)用完session.save(stu1)后,調(diào)用session.flush(),會發(fā)送sql語句到數(shù)據(jù)庫,再根據(jù)commit屬性為true,則保存stu1的操作已經(jīng)被持久到數(shù)據(jù)庫了,盡管后面的一條insert語句出了問題。
???? 因此,如果你想在HibernateCallback中使用session的事務(wù),需要如下寫:
public ? static ? void ?main(String?ss[])? {
????????CtxUtil.getBaseManager().getHibernateTemplate().execute(
new ?HibernateCallback()? {
????????????
public ?Object?doInHibernate(Session?session)? throws ?HibernateException,?SQLException? {
????????????????session.connection().setAutoCommit(
false );
????????????????
// 保存stu1
????????????????Student?stu1 = new ?Student();
????????????????stu1.setName(
" aaaa " ); // 在數(shù)據(jù)庫中,name字段不允許為null
????????????????session.save(stu1);
????????????????session.flush();
????????????????
????????????????Student?stu2?
= ? new ?Student();
????????????????session.save(stu2);
// 沒有設(shè)置name字段,預(yù)期會報出例外
?????????????????? session.flush();
????????????????session.connection().commit();
????????????????
// 至于session的關(guān)閉就不用我們操心了
???????????????? return ? null ;
????????????}

????????}
);

????}
運(yùn)行上述代碼,沒問題了。至此,可能有些讀者早就對代碼1不滿意了:為什么每次save()以后要調(diào)用flush()?這是有原因的。下面我們來看看把session.flush()去掉后會出什么問題。改掉后的代碼如下:
public ? static ? void ?main(String?ss[])?

?

?

?(轉(zhuǎn)載

HibernateTemplate中HibernateCallback的事務(wù)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 性做久久久久久 | 天天操综合网 | 久久精品首页 | 2021年无线乱码播放高清完整 | 成人在线小视频 | 热久久这里只有精品 | 9久9久女女免费精品视频在线观看 | 日本一二三区视频 | 亚洲国产视频网站 | 久久国产精品久久精品国产 | 91视频免费观看高清观看完整 | 免费色网 | 国产精品久久久久久日本 | 99精品免费视频 | 5278.cc| v11av在线播放 | 美国一级毛片片aaa 香蕉视频在线观看免费 | 色网站在线视频 | 免费午夜影片在线观看影院 | 成人在线精品视频 | 一色屋任你操 | 国产精品自线在线播放 | 波多野结衣亚洲 | 天天综合久久 | 欧美激情二区三区 | 奇米影视色 | 亚洲涩综合 | 免费观看成人碰视频公开 | 国产女主播喷出白浆视频 | 午夜电影在线观看 | 91蜜芽尤物福利在线观看 | 免费午夜影片在线观看影院 | 午夜影视免费片在线观看 | 波多野结衣VR全景3D | 午夜视频免费 成人 | 日韩成人av网站 | 91久久久久久久久久久久久久 | 国产一区二区欧美 | 国产欧美一区二区成人影院 | 久草在线观看福利视频 | 日本翁熄系列乱在线视频 |