黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

HibernateTemplate中HibernateCallback的事務

系統 2725 0

HibernateTemplate中HibernateCallback的事務

目的:使用HibernateTemplate執行execute(new HibernateCallback())方法,從HibernateCallback中得到session,在此session中做多個操作,并希望這些操作位于同一個事務中。
??????如果你這樣寫(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 " ); // ?在數據庫中,name字段不允許為null
????????????????session.save(stu1);
????????????????session.flush();//實際上,如果不是程序員"手癢"來調用這個flush(),HibernateTemplate中session的事務處理還是很方便的

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

????????}
);

????}
????? 你期望spring在執行完execute回調后,在關閉session的時候提交事務,想法是很好的,但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中,執行了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 ); // 把自動提交設為了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時,要在事務結束的時候,寫上一句: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();//重點代碼,它的作用是提交事務,并把connection的autocommit屬性恢復為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();//這段的作用是恢復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,并手動開啟事務關閉事務的話,完全可以保證你的事務(好像完全是廢話).
????? 但是,如果你用的是HibernateTemplate,如同源代碼1一樣,則不要指望spring在關閉session的時候為你提交事務(罪魁禍首就是在代碼1中調用了session.flush())。因為在使用代碼1時,spring中得到session的方式如下:
Session?session? = ?(entityInterceptor? != ? null ? ? ?sessionFactory.openSession(entityInterceptor)?:?sessionFactory
????????????????.openSession());
簡單地說它就是得到了一個session,而沒有對connection的autocommit()作任何操作,spring管理范圍內的session所持有的connection是autocommit=true的,spring借助這個屬性,在它關閉session時,提交數據庫事務。,因此如果你在源代碼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());
// 打印一下事務提交方式
????????????????
// ?保存stu1
????????????????Student?stu1? = ? new ?Student();
????????????????stu1.setName(
" aaaa " ); // ?在數據庫中,name字段不允許為null
????????????????session.save(stu1);
????????????????session.flush();

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

????????}
);

????}
???? 運行后,它打出的結果是true,也就是說,雖然保存stu2時會報出例外,但如果commit屬性為true,則每一個到達數據庫的sql語句會立即被提交。換句話說,在調用完session.save(stu1)后,調用session.flush(),會發送sql語句到數據庫,再根據commit屬性為true,則保存stu1的操作已經被持久到數據庫了,盡管后面的一條insert語句出了問題。
???? 因此,如果你想在HibernateCallback中使用session的事務,需要如下寫:
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 " ); // 在數據庫中,name字段不允許為null
????????????????session.save(stu1);
????????????????session.flush();
????????????????
????????????????Student?stu2?
= ? new ?Student();
????????????????session.save(stu2);
// 沒有設置name字段,預期會報出例外
?????????????????? session.flush();
????????????????session.connection().commit();
????????????????
// 至于session的關閉就不用我們操心了
???????????????? return ? null ;
????????????}

????????}
);

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

?

?

?(轉載

HibernateTemplate中HibernateCallback的事務


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

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

【本文對您有幫助就好】

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

發表我的評論
最新評論 總共0條評論