日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

新Hibernate SessionFactory().getCurrentSession()猫腻

發布時間:2024/4/17 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 新Hibernate SessionFactory().getCurrentSession()猫腻 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://liusu.iteye.com/blog/380397

今天要用Hibernate做點實驗,下載最新版得下來。解壓,建項目,從tutorial copy代碼。Tutorial里面提到說最新的Hibernate已經不需要用戶自己使用ThreadLocal得方式來管理和持有session,而把這種session管理方式內置了,只要依據依據配置就可以用了

Java代碼 ?
  • hibernate.current_session_context_class?=?jta/thread/managed?//Use?thread??
  • hibernate.current_session_context_class = jta/thread/managed //Use thread



    HibernateUtil.java

    Java代碼 ?
  • package?org.hibernate.tutorial.util; ??
  • ??
  • import?org.hibernate.SessionFactory; ??
  • import?org.hibernate.cfg.Configuration; ??
  • ??
  • public?class?HibernateUtil?{ ??
  • ??
  • ????private?static?final?SessionFactory?sessionFactory; ??
  • ??
  • ????static?{ ??
  • ????????try?{ ??
  • ????????????//?Create?the?SessionFactory?from?hibernate.cfg.xml ??
  • ????????????sessionFactory?=?new?Configuration().configure().buildSessionFactory(); ??
  • ????????}?catch?(Throwable?ex)?{ ??
  • ????????????//?Make?sure?you?log?the?exception,?as?it?might?be?swallowed ??
  • ????????????System.err.println("Initial?SessionFactory?creation?failed."?+?ex); ??
  • ????????????throw?new?ExceptionInInitializerError(ex); ??
  • ????????} ??
  • ????} ??
  • ??
  • ????public?static?SessionFactory?getSessionFactory()?{ ??
  • ????????return?sessionFactory; ??
  • ????} ??
  • ??
  • }??
  • package org.hibernate.tutorial.util;import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration;public class HibernateUtil {private static final SessionFactory sessionFactory;static {try {// Create the SessionFactory from hibernate.cfg.xmlsessionFactory = new Configuration().configure().buildSessionFactory();} catch (Throwable ex) {// Make sure you log the exception, as it might be swallowedSystem.err.println("Initial SessionFactory creation failed." + ex);throw new ExceptionInInitializerError(ex);}}public static SessionFactory getSessionFactory() {return sessionFactory;}}



    在使用的時候大概都是如此調用:

    Java代碼 ?
  • private?Long?createAndStoreEvent(String?title,?Date?theDate)?{ ??
  • ??
  • ????Session?session?=?HibernateUtil.getSessionFactory().getCurrentSession(); ??
  • ????session.beginTransaction(); ??
  • ??
  • ????Event?theEvent?=?new?Event(); ??
  • ????theEvent.setTitle(title); ??
  • ????theEvent.setDate(theDate); ??
  • ??
  • ????session.save(theEvent); ??
  • ??
  • ????session.getTransaction().commit(); ??
  • ??
  • ????return?theEvent.getId(); ??
  • }??
  • private Long createAndStoreEvent(String title, Date theDate) {Session session = HibernateUtil.getSessionFactory().getCurrentSession();session.beginTransaction();Event theEvent = new Event();theEvent.setTitle(title);theEvent.setDate(theDate);session.save(theEvent);session.getTransaction().commit();return theEvent.getId();}


    很順利,跑起來也一切正常。 我有一個查詢的需求。就是load一個Object對象需求。代碼如下:

    Java代碼 ?
  • private?Event?find(Event?event)?{ ??
  • ????Session?session?=?HibernateUtil.getSessionFactory().getCurrentSession(); ??
  • ????//session.beginTransaction(); ??
  • ??
  • ????Event?load?=?(Event)?session.load(Event.class,?event.getId()); ??
  • ??
  • ????//session.getTransaction().commit(); ??
  • ??
  • ????return?load; ??
  • }??
  • private Event find(Event event) {Session session = HibernateUtil.getSessionFactory().getCurrentSession();//session.beginTransaction();Event load = (Event) session.load(Event.class, event.getId());//session.getTransaction().commit();return load;}


    我一想,就是一普通的load和查詢操作,應該不用開閉Transaction了。但是卻報異常了:

    Java代碼 ?
  • org.hibernate.HibernateException:?get?is?not?valid?without?active?transaction??
  • org.hibernate.HibernateException: get is not valid without active transaction



    太抓狂了,就一些查詢操作也要開閉Transaction。公司有使用過Hiberbate的小伙子說的記得應該是不用的。想想唯一的使用的區別就是得到Session的代碼從

    Java代碼 ?
  • HibernateUtil.getSessionFactory().openSession();??
  • HibernateUtil.getSessionFactory().openSession();


    變為了

    Java代碼 ?
  • HibernateUtil.getSessionFactory().getCurrentSession();??
  • HibernateUtil.getSessionFactory().getCurrentSession();



    難道是這句HibernateUtil.getSessionFactory().getCurrentSession();有貓膩?
    Checkout源碼,跟進去看,果然:
    HibernateUtil.getSessionFactory().getCurrentSession()將Session交給一個CurrentSessionContext來處理,根據配置,使用的是ThreadLocalSessionContext這個東東。查看他的源碼:

    Java代碼 ?
  • public?final?Session?currentSession()?throws?HibernateException?{ ??
  • ????????Session?current?=?existingSession(?factory?); ??
  • ????????if?(current?==?null)?{ ??
  • ????????????current?=?buildOrObtainSession(); ??
  • ????????????//?register?a?cleanup?synch ??
  • ????????????current.getTransaction().registerSynchronization(?buildCleanupSynch()?); ??
  • ????????????//?wrap?the?session?in?the?transaction-protection?proxy ??
  • ????????????if?(?needsWrapping(?current?)?)?{ ??
  • ????????????????current?=?wrap(?current?);//Warp?Here???? ??
  • ????????????} ??
  • ????????????//?then?bind?it ??
  • ????????????doBind(?current,?factory?); ??
  • ????????} ??
  • ????????return?current; ??
  • ????}??
  • public final Session currentSession() throws HibernateException {Session current = existingSession( factory );if (current == null) {current = buildOrObtainSession();// register a cleanup synchcurrent.getTransaction().registerSynchronization( buildCleanupSynch() );// wrap the session in the transaction-protection proxyif ( needsWrapping( current ) ) {current = wrap( current );//Warp Here????}// then bind itdoBind( current, factory );}return current;}



    發現這里的Session已經是不純潔了,已經成宋祖德嘴里的女明星了。被包了。看看被包的過程,

    Java代碼 ?
  • protected?Session?wrap(Session?session)?{ ??
  • ????????TransactionProtectionWrapper?wrapper?=?new?TransactionProtectionWrapper(?session?); ??
  • ????????Session?wrapped?=?(?Session?)?Proxy.newProxyInstance( ??
  • ????????????????Session.class.getClassLoader(), ??
  • ????????????????SESS_PROXY_INTERFACES, ??
  • ????????????????wrapper ??
  • ????????????); ??
  • ????????//?yick!??need?this?for?proper?serialization/deserialization?handling... ??
  • ????????wrapper.setWrapped(?wrapped?); ??
  • ????????return?wrapped; ??
  • ????}??
  • protected Session wrap(Session session) {TransactionProtectionWrapper wrapper = new TransactionProtectionWrapper( session );Session wrapped = ( Session ) Proxy.newProxyInstance(Session.class.getClassLoader(),SESS_PROXY_INTERFACES,wrapper);// yick! need this for proper serialization/deserialization handling...wrapper.setWrapped( wrapped );return wrapped;}


    被包的很過分,直接換成代理了,看看代理人的嘴臉,這個代理人是TransactionProtectionWrapper

    看看他是用什么好東西包的:

    Java代碼 ?
  • /** ?
  • ?????????*?{@inheritDoc} ?
  • ?????????*/??
  • ????????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{ ??
  • ????????????try?{ ??
  • ????????????????//?If?close()?is?called,?guarantee?unbind() ??
  • ????????????????if?(?"close".equals(?method.getName())?)?{ ??
  • ????????????????????unbind(?realSession.getSessionFactory()?); ??
  • ????????????????} ??
  • ????????????????else?if?(?"toString".equals(?method.getName()?) ??
  • ?????????????????????????||?"equals".equals(?method.getName()?) ??
  • ?????????????????????????||?"hashCode".equals(?method.getName()?) ??
  • ?????????????????????????||?"getStatistics".equals(?method.getName()?) ??
  • ?????????????????????????||?"isOpen".equals(?method.getName()?)?)?{ ??
  • ????????????????????//?allow?these?to?go?through?the?the?real?session?no?matter?what ??
  • ????????????????} ??
  • ????????????????else?if?(?!realSession.isOpen()?)?{ ??
  • ????????????????????//?essentially,?if?the?real?session?is?closed?allow?any ??
  • ????????????????????//?method?call?to?pass?through?since?the?real?session ??
  • ????????????????????//?will?complain?by?throwing?an?appropriate?exception; ??
  • ????????????????????//?NOTE?that?allowing?close()?above?has?the?same?basic?effect, ??
  • ????????????????????//???but?we?capture?that?there?simply?to?perform?the?unbind... ??
  • ????????????????} ??
  • ????????????????else?if?(?!realSession.getTransaction().isActive()?)?{ ??
  • ????????????????????//?limit?the?methods?available?if?no?transaction?is?active ??
  • ????????????????????if?(?"beginTransaction".equals(?method.getName()?) ??
  • ?????????????????????????||?"getTransaction".equals(?method.getName()?) ??
  • ?????????????????????????||?"isTransactionInProgress".equals(?method.getName()?) ??
  • ?????????????????????????||?"setFlushMode".equals(?method.getName()?) ??
  • ?????????????????????????||?"getSessionFactory".equals(?method.getName()?)?)?{ ??
  • ????????????????????????log.trace(?"allowing?method?["?+?method.getName()?+?"]?in?non-transacted?context"?); ??
  • ????????????????????} ??
  • ????????????????????else?if?(?"reconnect".equals(?method.getName()?) ??
  • ??????????????????????????????||?"disconnect".equals(?method.getName()?)?)?{ ??
  • ????????????????????????//?allow?these?(deprecated)?methods?to?pass?through ??
  • ????????????????????} ??
  • ????????????????????else?{ ??
  • ????????????????????????throw?new?HibernateException(?method.getName()?+?"?is?not?valid?without?active?transaction"?); ??
  • ????????????????????} ??
  • ????????????????} ??
  • ????????????????log.trace(?"allowing?proxied?method?["?+?method.getName()?+?"]?to?proceed?to?real?session"?); ??
  • ????????????????return?method.invoke(?realSession,?args?); ??
  • ????????????} ??
  • ????????????catch?(?InvocationTargetException?e?)?{ ??
  • ????????????????if?(?e.getTargetException()?instanceof?RuntimeException?)?{ ??
  • ????????????????????throw?(?RuntimeException?)?e.getTargetException(); ??
  • ????????????????} ??
  • ????????????????else?{ ??
  • ????????????????????throw?e; ??
  • ????????????????} ??
  • ????????????} ??
  • ????????}??
  • /*** {@inheritDoc}*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// If close() is called, guarantee unbind()if ( "close".equals( method.getName()) ) {unbind( realSession.getSessionFactory() );}else if ( "toString".equals( method.getName() )|| "equals".equals( method.getName() )|| "hashCode".equals( method.getName() )|| "getStatistics".equals( method.getName() )|| "isOpen".equals( method.getName() ) ) {// allow these to go through the the real session no matter what}else if ( !realSession.isOpen() ) {// essentially, if the real session is closed allow any// method call to pass through since the real session// will complain by throwing an appropriate exception;// NOTE that allowing close() above has the same basic effect,// but we capture that there simply to perform the unbind...}else if ( !realSession.getTransaction().isActive() ) {// limit the methods available if no transaction is activeif ( "beginTransaction".equals( method.getName() )|| "getTransaction".equals( method.getName() )|| "isTransactionInProgress".equals( method.getName() )|| "setFlushMode".equals( method.getName() )|| "getSessionFactory".equals( method.getName() ) ) {log.trace( "allowing method [" + method.getName() + "] in non-transacted context" );}else if ( "reconnect".equals( method.getName() )|| "disconnect".equals( method.getName() ) ) {// allow these (deprecated) methods to pass through}else {throw new HibernateException( method.getName() + " is not valid without active transaction" );}}log.trace( "allowing proxied method [" + method.getName() + "] to proceed to real session" );return method.invoke( realSession, args );}catch ( InvocationTargetException e ) {if ( e.getTargetException() instanceof RuntimeException ) {throw ( RuntimeException ) e.getTargetException();}else {throw e;}}}



    呵呵,幾乎所有正常的操作都必須在transcation.isActive()條件下才能執行。我要用的get,load,save, saveOrUpdate,list都在此列。

    到此為止,算明白了。 尋到根了,Hibernate的理由是:

    org.hibernate.context.ThreadLocalSessionContext

    A CurrentSessionContext impl which scopes the notion of current session by the current thread of execution. Unlike the JTA counterpart, threads do not give us a nice hook to perform any type of cleanup making it questionable for this impl to actually generate Session instances. In the interest of usability, it was decided to have this default impl actually generate a session upon first request and then clean it up after the org.hibernate.Transaction associated with that session is committed/rolled-back. In order for ensuring that happens, the sessions generated here are unusable until after Session.beginTransaction() has been called. If close() is called on a session managed by this class, it will be automatically unbound.

    Additionally, the static bind and unbind methods are provided to allow application code to explicitly control opening and closing of these sessions. This, with some from of interception, is the preferred approach. It also allows easy framework integration and one possible approach for implementing long-sessions.

    The buildOrObtainSession, isAutoCloseEnabled, isAutoFlushEnabled, getConnectionReleaseMode, and buildCleanupSynch methods are all provided to allow easy subclassing (for long-running session scenarios, for example).

    Author:

    Steve Ebersole

    用別人的東西得小心,知道他背后干了什么很重要啊。

    ==============

    http://www.cnblogs.com/liuyang-1037/archive/2009/03/26/1422254.html

    Configuration:

    負責管理Hibernate的配置信息,這些配置信息都是從配置文件hibernate.cfg.xml或者Hibernate.properties讀取的,當然也可以自定義文件名稱,只要在實例化Configuration的時候指定具體的路徑就可以了;

    ?


    SessionFactiory:

    Configuration的實例會根據當前的配置信息,構造SessionFactory實例。SessionFactory是線程安全的,一般情況下一個應用中一個數據庫共享一個SessionFactory實例。

    ?構建SessionFactory
    Hibernate的SessionFactory接口提供Session類的實例,Session類用于完成對數據庫的操作。由于SessionFactory實例是線程安全
    的(而Session實例不是線程安全的),所以每個操作都可以共用同一個SessionFactory來獲取Session。

    Hibernate配置文件分為兩種格式,一種是xml格式的配置文件,另一種是Java屬性文件格式的配置文件,因此構建SessionFactory也有兩種方法,下面分別介紹。

    2.6.1? 從XML文件讀取配置信息構建SessionFactory
    從XML文件讀取配置信息構建SessionFactory的具體步驟如下。

    (1)創建一個Configuration對象,并通過該對象的configura()方法加載Hibernate配置文件,代碼如下。

    Configuration config = new Configuration().configure();

    configura()方法:用于告訴Hibernate加載hibernate.cfg.xml文件。Configuration在實例化時默認加載classpath中的hibernate.cfg.xml,當然也可以加載名稱不是hibernate.cfg.xml的配置文件,例如wghhibernate.cfg.xml,可以通過以下代碼實現

    Configuration config = new Configuration().configure("wghhibernate.cfg.xml");

    (2)完成配置文件和映射文件的加載后,將得到一個包括所有Hibernate運行期參數的Configuration實例,通過Configuration實例的buildSessionFactory()方法可以構建一個惟一的SessionFactory,代碼如下。

    SessionFactory sessionFactory = config.buildSessionFactory();

    構建SessionFactory要放在靜態代碼塊中,因為它只在該類被加載時執行一次。一個典型的構建SessionFactory的代碼如下。

  • import?org.hibernate.*; ??
  • ??
  • import?org.hibernate.cfg.*; ??
  • ??
  • public?class?CoreSession?{ ??
  • ??
  • static?SessionFactory?sessionFactory; ??
  • //注意到這里的SessionFactory都是static的
  • //初始化Hibernate,創建SessionFactory實例,只在該類被加載到內存時執行一次 ??
  • ??
  • static{ ??
  • ??
  • ????try{ ??
  • ??
  • ?????????Configuration?config?=?new?Configuration().configure(); ??
  • ??
  • ?????????sessionFactory?=?config.buildSessionFactory(); ??
  • ??
  • ????}?catch?(Exception?e)?{ ??
  • ??
  • ????????System.out.println(e.getMessage()); ??
  • ??
  • ????} ??
  • ??
  • } ??
  • ??
  • } ??
  • 2.6.2? 從Java屬性文件讀取配置信息構建SessionFactory
    從Java屬性文件讀取配置信息構建SessionFactory的具體步驟如下。

    (1)創建一個Configuration對象,此時Hibernate會默認加載classpath中的配置文件hibernate.properties,代碼如下。

    Configuration config = new Configuration();

    (2)由于在配置文件中缺少相應的配置映射文件的信息,所以此處需要通過編碼方式加載,這可以通過Configuration對象的

    addClass()方法實現,具體代碼如下。

    config.addClass(BranchForm.class);

    addClass()方法用于加載實體類。

    (3)完成配置文件和映射文件的加載后,將得到一個包括所有Hibernate運行期參數的Configuration實例,通過Configuration實例

    的buildSessionFactory()方法可以構建一個惟一的SessionFactory,代碼如下。

    SessionFactory sessionFactory = config.buildSessionFactory();

    構建SessionFactory要放在靜態代碼塊中,因為它只需在該類被加載時執行一次,一個典型的構建SessionFactory的代碼如下。

  • import?org.hibernate.*; ??
  • ??
  • import?org.hibernate.cfg.*; ??
  • ??
  • public?class?CoreSession?{ ??
  • ??
  • static?SessionFactory?sessionFactory; ??
  • ??
  • //初始化Hibernate,創建SessionFactory實例,只在該類被加載到內存時執行一次 ??
  • ??
  • static{ ??
  • ??
  • ????try{ ??
  • ??
  • ???????Configuration?config?=?new?Configuration(); ??
  • ??
  • ????????config.addClass(BranchForm.class); ??
  • ??
  • ????????sessionFactory?=?config.buildSessionFactory(); ??
  • ??
  • ????}?catch?(Exception?e)?{ ??
  • ??
  • ????????System.out.println(e.getMessage()); ??
  • ??
  • ????} ??
  • ??
  • } ??
  • ??
  • }

  • Session:

    一般的持久化方法(CRUD)都是通過Session來調用的,Session是非線程安全的。

    Session的創建與關閉 :Session是一個輕量級對象,通常將每個Session實例和一個數據庫事務綁定,也就是每執行一個數據庫事務,都應該先創建一個新的Session實例,在使用Session后,還需要關閉Session。

    Session的創建

    創建SessionFactory后,就可以通過SessionFactory創建Session實例,通過SessionFactory創建Session實例的代碼如下。

    Session session=sessionFactory.openSession();

    創建Session后,就可以通過創建的Session進行持久化操作了。

    Session的關閉

    在創建Session實例后,不論是否執行事務,最后都需要關閉Session實例,釋放Session實例占用的資源。

    關閉Session實例的代碼如下:session.close();

    ?

    總結

    以上是生活随笔為你收集整理的新Hibernate SessionFactory().getCurrentSession()猫腻的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。