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

          常用鏈接

          留言簿(19)

          隨筆檔案(115)

          文章檔案(4)

          新聞檔案(1)

          成員連接

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          ????? 作為EJB3.0的一部分,JPA是一個(gè)好東西。其簡單的配置方式及強(qiáng)大的默認(rèn)配置支持,使其可以輕松自由的存在于輕量與重量之間,如果現(xiàn)在您的JavaEE項(xiàng)目,不管是選擇輕量級構(gòu)架還是重量級構(gòu)架,如果持久層不選擇使用JPA,而是用一些ORM框架(如Hibernate、TopLink)的專用API,那么在將來的某一天一定會(huì)為這個(gè)選擇而說出至尊寶那句“假如上天再給我一個(gè)機(jī)會(huì)…”的至理名言。
          ?????? 下面是一個(gè)簡單的Entity,是對一個(gè)CMS系統(tǒng)中,關(guān)于樹狀信息目錄實(shí)體類的定義,包括了一些詳細(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也不是完美的,在使用的過程中難免都會(huì)出這樣那樣的問題,這就需要我們程序員具有格物致知的本領(lǐng),在應(yīng)用中靈活應(yīng)付這些問題。
            這里例舉一個(gè)緩遲加載的問題,以上面的新聞目錄Entity為例。對于parnet與children這個(gè)一對多的雙向關(guān)聯(lián),為了提高系統(tǒng)效率,children默認(rèn)使用的是緩遲加載的方式。在一些輕量級的構(gòu)架中,由于脫離了J2EE容器及事務(wù)支持,經(jīng)常會(huì)出現(xiàn)Entity脫離了Persitence Context,變成了detach或EntityManager關(guān)閉,導(dǎo)致一些我們預(yù)想中的一些功能無法正常運(yùn)行。
            最常見的就是在使用MVC框架的時(shí)候,在表示層無法加載需要緩遲加載的數(shù)據(jù)。比如,在一個(gè)基于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()方法的時(shí)候,將會(huì)用到緩遲加載,由于Spring的事務(wù)是配置在service層的,因此在執(zhí)行service.queryDirsByConditions方法完成后就關(guān)閉了事務(wù)。因此運(yùn)行程序就會(huì)出現(xiàn)類似下面的錯(cuò)誤信息:

          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都會(huì)有這樣的問題,問題的核心是在事務(wù)啟動(dòng)及結(jié)束上,由于我們都習(xí)慣于在service層而非mvc配置及使用事務(wù),導(dǎo)致了這樣的問題。解決的辦法其實(shí)很簡單,就是把事務(wù)的啟動(dòng)放到mvc層,讓mvc層的controller來開啟事務(wù),而讓業(yè)務(wù)層的方法加入的事務(wù)中。比如,在EasyJWeb中,可以通過如下的配置來實(shí)現(xiàn)實(shí)現(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"/>

            只需要這樣簡單的配置,你會(huì)驚奇的發(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 啊啊啊啊
          解決的辦法其實(shí)很簡單,就是把事務(wù)的啟動(dòng)放到mvc層,讓mvc層的controller來開啟事務(wù),而讓業(yè)務(wù)層的方法加入的事務(wù)中。

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

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 辽源市| 南宫市| 陈巴尔虎旗| 嘉禾县| 孟津县| 保德县| 梅河口市| 定西市| 山东| 崇礼县| 潼关县| 乌鲁木齐县| 田东县| 丰原市| 碌曲县| 锡林浩特市| 儋州市| 周宁县| 镇赉县| 宝应县| 高平市| 明水县| 专栏| 美姑县| 石城县| 突泉县| 刚察县| 九江县| 阿瓦提县| 柘城县| 双辽市| 防城港市| 逊克县| 东莞市| 桃园市| 山西省| 靖宇县| 丹阳市| 瑞金市| 濉溪县| 安龙县|