隨筆 - 115  文章 - 481  trackbacks - 0
          <2007年3月>
          25262728123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿(19)

          隨筆檔案(115)

          文章檔案(4)

          新聞檔案(1)

          成員連接

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          ????? 作為EJB3.0的一部分,JPA是一個好東西。其簡單的配置方式及強大的默認(rèn)配置支持,使其可以輕松自由的存在于輕量與重量之間,如果現(xiàn)在您的JavaEE項目,不管是選擇輕量級構(gòu)架還是重量級構(gòu)架,如果持久層不選擇使用JPA,而是用一些ORM框架(如Hibernate、TopLink)的專用API,那么在將來的某一天一定會為這個選擇而說出至尊寶那句“假如上天再給我一個機會…”的至理名言。
          ?????? 下面是一個簡單的Entity,是對一個CMS系統(tǒng)中,關(guān)于樹狀信息目錄實體類的定義,包括了一些詳細(xì)的映射的配置信息。
          @Entity
          public?class?NewsDir?{
          ????@Id
          ????@GeneratedValue(strategy?
          =?GenerationType.TABLE)
          ????
          private?Long?id;//?主鍵

          ????@Column(unique?
          =?true,?nullable?=?false,?length?=?16)
          ????
          private?String?sn;//?目錄編號

          ????
          private?String?title;?//?目錄名稱

          ????@OneToMany(mappedBy?
          =?"parent",?cascade?=?javax.persistence.CascadeType.REMOVE)
          ????
          private?List<NewsDir>?children?=?new?java.util.ArrayList<NewsDir>();//?下級目錄

          ????@ManyToOne
          ????
          private?NewsDir?parent;//?父級目錄



          }

            當(dāng)然,跟任何其它優(yōu)秀的技術(shù)一樣,JPA也不是完美的,在使用的過程中難免都會出這樣那樣的問題,這就需要我們程序員具有格物致知的本領(lǐng),在應(yīng)用中靈活應(yīng)付這些問題。
            這里例舉一個緩遲加載的問題,以上面的新聞目錄Entity為例。對于parnet與children這個一對多的雙向關(guān)聯(lián),為了提高系統(tǒng)效率,children默認(rèn)使用的是緩遲加載的方式。在一些輕量級的構(gòu)架中,由于脫離了J2EE容器及事務(wù)支持,經(jīng)常會出現(xiàn)Entity脫離了Persitence Context,變成了detach或EntityManager關(guān)閉,導(dǎo)致一些我們預(yù)想中的一些功能無法正常運行。
            最常見的就是在使用MVC框架的時候,在表示層無法加載需要緩遲加載的數(shù)據(jù)。比如,在一個基于EasyJWeb的mvc應(yīng)用中,action中的方法如下:

          public?Page?doList(WebForm?form,?Module?module)?{
          ????????NewsDirQueryObject?ndqo?
          =?new?NewsDirQueryObject();
          ????????form.toPo(ndqo);
          ????????ndqo.setDel(
          true);
          ????????IPageList?pageList?
          =?service.queryDirsByConditions(ndqo);
          ????????CommUtilForTeaec.saveIPageList2WebForm(pageList,?form);
          ????????form.addResult(
          "dirPath",?this.getDirPath(form));
          ????????
          return?module.findPage("list");
          ????}

          在模板文件中有如下內(nèi)容:
          #foreach($info in ${dir.children})
          目錄名稱:${info.title}
          #end

          關(guān)于業(yè)務(wù)邏輯層Bean的配置:

          ?

          <aop:config>
          ????????????????
          <aop:pointcut?id="CmsManage"
          ????????????expression
          ="execution(*?com.easyjf.cms.service.*.*(..))"?/>
          <aop:advisor?advice-ref="cmsManageAdvice"
          ????????????pointcut-ref
          ="CmsManage"?/>????????????
          <tx:advice?id="cmsManageAdvice"
          ????????transaction-manager
          ="transactionManager">
          ????????
          <tx:attributes>
          ????????????
          <tx:method?name="get*"?propagation="SUPPORTS"
          ????????????????read-only
          ="true"?/>
          ????????????
          <tx:method?name="query*"?propagation="SUPPORTS"
          ????????????????read-only
          ="true"?/>
          ????????????
          <tx:method?name="*"?propagation="REQUIRED"?/>
          ????????
          </tx:attributes>
          ????
          </tx:advice>
          <bean?id="cmsManageService"
          ????????class
          ="com.easyjf.cms.service.impl.CmsManageServiceImpl">????
          ????????
          <property?name="newsDirDao"?ref="newsDirDao"?/>
          ????
          </bean>

          在這里,當(dāng)mvc層執(zhí)行到$!info.getChildren()方法的時候,將會用到緩遲加載,由于Spring的事務(wù)是配置在service層的,因此在執(zhí)行service.queryDirsByConditions方法完成后就關(guān)閉了事務(wù)。因此運行程序就會出現(xiàn)類似下面的錯誤信息:

          2007-03-28?00:39:35,750?ERROR?[org.hibernate.LazyInitializationException]?-?failed?to?lazily?initialize?a?collection?of?role:?com.easyjf.cms.domain.NewsDir.children,?no?session?or?session?was?closed
          org.hibernate.LazyInitializationException:?failed?to?lazily?initialize?a?collection?of?role:?com.easyjf.cms.domain.NewsDir.children,?no?session?or?session?was?closed
          ?at?org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:
          358)
          ?at?org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:
          350)
          ?at?org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:
          97)

            使用其它的mvc如struts、webwork乃至spring mvc都會有這樣的問題,問題的核心是在事務(wù)啟動及結(jié)束上,由于我們都習(xí)慣于在service層而非mvc配置及使用事務(wù),導(dǎo)致了這樣的問題。解決的辦法其實很簡單,就是把事務(wù)的啟動放到mvc層,讓mvc層的controller來開啟事務(wù),而讓業(yè)務(wù)層的方法加入的事務(wù)中。比如,在EasyJWeb中,可以通過如下的配置來實現(xiàn)實現(xiàn)在action中開啟事務(wù):
            在Spring配置文件中配置EasyJWeb的核心處理器,并把process方法添加到事務(wù)中,配置文件如下:

          ?

          <aop:config>
          ????????
          <aop:pointcut?id="easyjwebProcessor"
          ????????????expression
          ="execution(*?com.easyjf.web.RequestProcessor.process(..))"?/>
          ????????
          <aop:advisor?advice-ref="txEasyjwebProcessorAdvice"
          ????????????pointcut-ref
          ="easyjwebProcessor"?/>
          ????
          </aop:config>
          ????
          <tx:advice?id="txEasyjwebProcessorAdvice"
          ????????transaction-manager
          ="transactionManager">
          ????????
          <tx:attributes>
          ????????????
          <tx:method?name="*"?propagation="REQUIRED"?read-only="true"?/>
          ????????
          </tx:attributes>
          ????
          </tx:advice>
          ????
          <bean?name="EasyJWeb-Processor"?class="com.easyjf.web.core.DefaultRequestProcessor"/>

            只需要這樣簡單的配置,你會驚奇的發(fā)現(xiàn),所有緩遲加載及其它由Persitence Context無效而引起的問題均解決了。

          ?????? 關(guān)于easyjweb與spring的集成,有興趣的朋友請參考stef_wu的《在EasyJWeb使用spring容器》一文。

          (本文作者:EasyJF開源??大峽 歡迎轉(zhuǎn)載,轉(zhuǎn)載請保留作者聲明,謝謝!)

          posted on 2007-03-28 02:15 簡易java框架 閱讀(1656) 評論(2)  編輯  收藏

          FeedBack:
          # re: 讓spring幫助你在MVC層解決JPA的緩遲加載問題  2007-03-28 08:37 啊啊啊啊
          解決的辦法其實很簡單,就是把事務(wù)的啟動放到mvc層,讓mvc層的controller來開啟事務(wù),而讓業(yè)務(wù)層的方法加入的事務(wù)中。

          何時,對什么啟用事務(wù),取決于該操作是否需要事務(wù)。如果的確要將事務(wù)加在c層,那么controller中調(diào)用的操作必需要是一個事務(wù)操作,否則不該回滾的回滾了,這可就麻煩大了  回復(fù)  更多評論
            
          # re: 讓spring幫助你在MVC層解決JPA的緩遲加載問題  2007-03-28 09:14 大峽1
          樓上分析得有道理,不過就算在輕量的應(yīng)用里面,事務(wù)其實是很靈活的,給Controller加事務(wù),并不表示業(yè)務(wù)層所有的事務(wù)都必須加入到同一個事務(wù)中,如果自己愿意,更不會讓所有的操作回滾。當(dāng)然,我想這只是解決這一問題方案的一種,如果有更好的方案,歡迎大家提出來研究。  回復(fù)  更多評論
            

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 漳浦县| 郑州市| 北票市| 丽江市| 江永县| 天台县| 图片| 南宁市| 万全县| 鄂州市| 福建省| 景宁| 尖扎县| 泗阳县| 遂宁市| 深泽县| 南昌市| 黄陵县| 鄂伦春自治旗| 定安县| 顺平县| 佳木斯市| 巴南区| 垫江县| 噶尔县| 富平县| 桂林市| 翁牛特旗| 伊春市| 赤城县| 景泰县| 荆州市| 浦城县| 改则县| 曲松县| 淅川县| 康保县| 休宁县| 玛沁县| 石柱| 上虞市|