乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Hibernate從2升級到3不支持Oracle8外連接( )的解決辦法

       WindySky 2007-10-10

      最近接手了一個要維護(hù)的項(xiàng)目,是用Hibernate2+Oralce8寫成的,因?yàn)榭吹紿ibernate3頁出來這么久了,而且也感覺Hibernate3有它的許多新的特性,如批量刪除和更新,新的HQL語法解析器AST。

      升級過程大致按照孫衛(wèi)琴的那篇文章 如何把Hibernate2.1升級到Hibernate3.0?來做,該替換的替換完,該設(shè)置的設(shè)置完,程序一跑,當(dāng)程序執(zhí)行到向下面這種查詢的時候(Oracle所特有的外連接查詢),報(bào)錯。

      語句為:(描述為類似語句,把項(xiàng)目中的實(shí)際表名隱去了)

      session.createQuery("select t1.c1,t2.c1 from Table1 t1,Table2 t2 where t1.c1=t2.c1(+)").list();

      出錯信息為:
      org.hibernate.hql.ast.QuerySyntaxException: unexpected token: ) near line 1, column 106 [select t1.c1,t2.c1 from Table1 t1,Table2 t2 where t1.c1=t2.c1(+)]
       at org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:31)
       at org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:24)
       at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:59)
       at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:258)
       at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:157)
       at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:111)
       at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
       at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:56)
       at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:72)
       at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:133)
       at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:112)
       at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1623)

      再回頭看看孫衛(wèi)琴的那篇升級注意事項(xiàng)中 1.3 查詢語句的變化 提到Hibernate3.0 采用新的基于ANTLR的HQL/SQL查詢翻譯器ASTQueryTranslator,它已經(jīng)不支持像Oracle8i和Sybase11那樣的 THETA-STYLE 連接查詢方言。

      解決這一問題的辦法有兩種:
      (1)改為使用支持ANSI-STYLE連接查詢的方言,像 LEFT OUTER JOIN .. ON ..的寫法
      (2)也可改用 Hibernate2的查詢翻譯器,可在 hibernate.cfg.xml 中進(jìn)行配置。

      因第一種方法,需要在映射文件中配置PO 間的X 對X的關(guān)聯(lián)關(guān)系才能用,如過哪位朋友在不配置 PO 間關(guān)聯(lián)關(guān)系時也能用LEFT OUTER JOIN .. ON ..的寫法連接查詢,能告訴我怎么做的號嗎?讓咱也學(xué)一招,先謝了!

      所以想想還是在 hibernate.cfg.xml 中配置

      <property name="query.factory_class">
      org.hibernate.hql.classic.ClassicQueryTranslatorFactory
      </property>
        

      注:hibernate3默認(rèn)的HQL語法翻譯器的配置為:

      <property name="query.factory_class">
      org.hibernate.hql.classic.ASTQueryTranslatorFactory
      </property>
        

      使用傳統(tǒng)的hibernat2所用的HQL語法翻譯器。然后程序再跑一跑,剛剛那個(+)的地方是沒有錯了,可是新麻煩有冒起來了,程序執(zhí)行到

        session.createQuery("delete User u where u.id=4").executeUpdate();

      有報(bào)錯了:
      org.hibernate.QueryException: query must begin with SELECT or FROM: delete [delete com.unmi.User where u.id=4]

      原來舊的HQL語法解析器不支持 delete User 的寫法,hibernate2在刪除持久化對象時必須寫成

      session.delete("delete User u where u.id=4");

      然而新的 org.hibernate.Session 的接口方法已去除了 Session.delete(String hql)方法,看來這條路也是受阻了。正是兩頭受難,無奈之時暫時放棄了升級的念頭,把該還原的地方都恢復(fù)舊模樣了。

      過了好一段時間,也就是個把月吧……

      心里總也覺不甘心,覺得事情總有解決的辦法,于是采用了終極辦法:從原代碼下手,進(jìn)行單步的跟蹤,看看hibernate3何時進(jìn)行HQL到SQL的轉(zhuǎn)換,何時取用配置的語法翻譯器。

      下面要解決的一個課題就是:

      如何讓Hibernate3既能使用新的Delete和Update語法,又能使用 Oracle Theta-Style 的 t1.c1=t2.c1(+)外連接寫法

      其中的語法翻譯器如何把傳入的一條HQL語句拆解進(jìn)行分析這里就不詳敘,不過最好還是要明白一點(diǎn):
      Classic語法翻譯器會把傳入的t1.c1=t2.c1(+)中的(+)作為一個整體,不拆開來,而AST語法分析器卻會把其中的(+)依括號拆成 ”(” , ”+” , ”)” 三部分。

      我們首先來看看HQL語法翻譯工廠接口 QueryTranslatorFatory 有兩個接口方法:

              public QueryTranslator createQueryTranslator(String queryIdentifier, String queryString,
                                                                                        Map filters, SessionFactoryImplementor factory);

               
      public QueryTranslator createFilterTranslator(String queryIdentifier, String queryString,
                                                                                        Map filters, SessionFactoryImplementor factory);

      調(diào)用以上兩個方法只在類 HQLQueryPlan的構(gòu)造函數(shù)中(五個參數(shù)的那個)

              protected HQLQueryPlan(String hql, String collectionRole, boolean shallow,
                                                           Map enabledFilters, SessionFactoryImplementor factory)
              {
              ......
              }

      這個構(gòu)造函數(shù)接收你寫的HQL語句還有一個 SessionFactoryImplementor (extends SessionFactory),這個SessionFactory持有hibernate.cfg.xml的配置項(xiàng)HQL語法翻譯器。
      讀這個構(gòu)造函數(shù)的代碼,我們發(fā)現(xiàn)有兩段代碼

      translators[i] = factory.getSettings().getQueryTranslatorFactory()
                                                         .createQueryTranslator(hql,concreteQueryStrings[i],enabledFilters, factory );

      translators[i] = factory.getSettings().getQueryTranslatorFactory()
                                                         .createFilterTranslator(hql, concreteQueryStrings[i], enabledFilters, factory );

      它們的職能是獲取SessionFactory (hibernate.cfg.xml)所配置的HQL語法分析器,這也就是我們的切入點(diǎn),我們所希望的事情是:
      當(dāng)構(gòu)造HQLQueryPlan時,發(fā)現(xiàn)傳給的hql是一個Oracle 那樣的THETA-STYLE 連接查詢語句(即像有(+)那樣的語句),我們就繞開在 hibernate.cfg.xml 所配置的AST HQL語法翻譯器,而是采用能夠理解這種語法的傳統(tǒng)的語法翻譯器。
      因此我們只要把 HQLQueryPlan類的這個構(gòu)造函數(shù)中的

      if ( collectionRole == null) { …………………………… }

      改為如下:

      if (collectionRole == null)

                                {
                      translators[i] =                         .createQueryTranslator(hql, concreteQueryStrings[i], enabledFilters, factory); 
              } 
                      {
                      translators[i] = factory.getSettings().getQueryTranslatorFactory()
                                                      .createQueryTranslator(hql, concreteQueryStrings[i], enabledFilters, factory); 
              } 

              translators[i].compile(factory.getSettings().getQuerySubstitutions(), shallow);
      }

                               {
                      translators[i] =
                                                     .createFilterTranslator(hql, concreteQueryStrings[i], enabledFilters, factory);     
              } 
                      {
                      translators[i] = factory.getSettings() .getQueryTranslatorFactory()
                                                      .createFilterTranslator(hql, concreteQueryStrings[i], enabledFilters, factory); 
              } 
                 
              ((FilterTranslator) translators[i])
                                                .compile(collectionRole, factory.getSettings().getQuerySubstitutions(), shallow);
      }
      //如果hql語句中使用Oralce式的外連接方式就用傳統(tǒng)的語法翻譯器 
      if (hql.replaceAll("\\s*", "").indexOf("(+)") != -1
      new ClassicQueryTranslatorFactory()
      else 
      else
      //如果hql語句中使用Oralce式的外連接方式就用傳統(tǒng)的語法翻譯器 
      if (hql.replaceAll("\\s*", "").indexOf("(+)") != -1
      new ClassicQueryTranslatorFactory()else 

      改完之后,把編譯后的HQLQueryPlan.class覆蓋到hibernate3.jar包中相應(yīng)的目錄中即可,或者把這個類放在classes下相應(yīng)的目錄中,在WEB應(yīng)用程序中 WEB-INF/classes中的類是優(yōu)先于jar包中的類先加載。
      以上做法兩種有些矛盾的問題也就得到解決了,org.hibernate.Session既可以執(zhí)行Hibernate3 引入的 delete/update語句,還能夠在 Oracle/Sybase中用(+)外連接方式而不需要配置X對X的連接關(guān)系。

      下面再介紹一種折中的解決辦法,不知大家注意到?jīng)]有,在Hibernate3中的

      org.hibernate.SessionFactory的openSession方法返回的是一個
      org.hibernate.classic.Session對象,而org.hibernate.classic.Session是繼承自org.hibernate.Session的。

          public org.hibernate.classic.Session openSession(Connection connection);
      public interface Session extends org.hibernate.Session

         

      而通常我們順應(yīng)新潮流,是用org.hibernate.Session去引用SessionFactory的方法openSession()的返回值的,于是我們想用 session.delete(sql) 方法時,就把返回的Session實(shí)例轉(zhuǎn)型為 org.hibernate.classic.Session即可。

      ((org.hibernate.classic.Session)session).delete("from User u where u.id=4");

      如果你也想用原始Session的其他已被擯棄的方法,亦可如此這般做。

      當(dāng)然了,在另一方面要讓Hibernate 能支持 Oracle/Sybase中用(+)外連接方式, 您還是要使

      用傳統(tǒng)的語法分析器,他將不能理解新的delete/update語句,很遺憾。
      所以為了順應(yīng)新的潮流的發(fā)展,應(yīng)使用第一種方法。要知道hibernate3中的delete/update語句可比2中的session.delete(hql)方法效率高,hibernate3中直接向數(shù)據(jù)庫發(fā)一個delete語句,而在hibernate2中的delete(hql)方法是需要首先加載對象在刪除,確有些多次一舉,不過又是也有它的道理,update也類此。

      在補(bǔ)充一個:hibernate會對 hql 對應(yīng)的 HQLQueryPlan 進(jìn)行緩沖的,在類 QueryPlanCache 中處理

              HQLQueryPlanKey key = new HQLQueryPlanKey( queryString, shallow, enabledFilters );
              HQLQueryPlan plan = ( HQLQueryPlan ) planCache.get ( key );
                               
             
      if ( plan == null ){ ..................}

      依據(jù)queryString(hql)生成key值.


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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多