小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Spring聲明式事務(wù)管理出錯(cuò)示例與解決之道

 WindySky 2009-04-16
前言
今天,發(fā)現(xiàn)了一個(gè)以前寫(xiě)的使用Spring聲明式事務(wù)管理的程序爆出了數(shù)據(jù)庫(kù)連接錯(cuò)誤,感覺(jué)是非常典型的一個(gè)誤用Spring聲明式事務(wù)管理的例子,拿出來(lái)為大家點(diǎn)評(píng)一下。
請(qǐng)先閱讀我之前寫(xiě)的關(guān)于事務(wù)管理的文章:事務(wù)管理最佳實(shí)踐全面解析事務(wù)管理最佳實(shí)踐多余的話之一每次請(qǐng)求,一次數(shù)據(jù)庫(kù)連接,一次事務(wù)是不是金科玉律?, 事務(wù)管理最佳實(shí)踐多余的話之二:Transaction后綴給聲明式事務(wù)管理帶來(lái)的好處
 
 
Spring聲明式事務(wù)管理出錯(cuò)示例
這個(gè)應(yīng)用程序是使用Spring管理的iBatis程序。事務(wù)使用了Spring的聲明式事務(wù)管理。
爆出了如下的錯(cuò)誤:
Caused by:
java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
 
at com.withub.wcms.manage.collectnews.systemNewsinfo.dao.WcmsSystemNewsinfoDao.add(WcmsSystemNewsinfoDao.java:50)
    at com.withub.wcms.manage.collectnews.systemNewsinfo.service.WcmsSystemNewsinfoService.saveOrUpdate(WcmsSystemNewsinfoService.java:103)
    at com.withub.wcms.manage.collectnews.systemNewsinfo.service.WcmsSystemNewsinfoService.formatRawInfoToHtml(WcmsSystemNewsinfoService.java:89)
 
可以看出,出現(xiàn)的錯(cuò)誤是,Spring管理下的iBatis使用的數(shù)據(jù)庫(kù)連接是只讀的。而在DAO類(lèi)的方法中,卻使用了修改數(shù)據(jù)庫(kù)的iBatis方法。
 
源代碼:
WcmsSystemNewsinfoDao類(lèi)的源代碼就不列出來(lái)了。這個(gè)Dao類(lèi)的add方法使用了iBatis的update方法,更新數(shù)據(jù)庫(kù)數(shù)據(jù)。
下面是WcmsSystemNewsinfoService類(lèi)的部分相關(guān)調(diào)用方法的源代碼:
public String formatRawInfoToHtml(String infoRawId) throws Exception{
       WcmsSystemNewsinfoRawModule wcmsSystemNewsinfoRawModule=new WcmsSystemNewsinfoRawModule();
       wcmsSystemNewsinfoRawModule.setInfoId(infoRawId);
       //原表數(shù)據(jù)
        wcmsSystemNewsinfoRawModule=this.getManageNewsinfoService().queryRawInfoById(wcmsSystemNewsinfoRawModule);
       WcmsSystemNewsinfoModule wcmsSystemNewsinfoModule=new WcmsSystemNewsinfoModule();
       //目標(biāo)表數(shù)據(jù)
       BeanUtils.copyProperties(wcmsSystemNewsinfoModule, wcmsSystemNewsinfoRawModule);
      
       wcmsSystemNewsinfoModule.setInfoRawId(wcmsSystemNewsinfoRawModule.getInfoId());
       wcmsSystemNewsinfoModule.setInfoId(null);
      
       returnthis.saveOrUpdate(wcmsSystemNewsinfoModule);
      
    }
    /**
     *需要把目標(biāo)表Model信息保存在目標(biāo)表中。如果該記錄已存在,則更新,否則,新增!
     *
     *@parammodule
     *@throwsException
     */
    public String saveOrUpdate(WcmsSystemNewsinfoModule module) throws Exception{
       WcmsSystemNewsinfoModule loadModule=this.getWcmsSystemNewsinfoDao().selectWcmsSystemNewsinfoModuleByInfoRawId(module.getInfoRawId());
       String infoId=null;
       if(loadModule==null){
           //插入
           infoId=this.getWcmsSystemNewsinfoDao().add(module);
          
       }else{
           //更新
           /**
            *更新
            *1,找到主鍵條件
            */
           infoId=loadModule.getInfoId();
           module.setInfoId(loadModule.getInfoId());
           this.getWcmsSystemNewsinfoDao().updateProcessedInfo(module);
          
       }
       return infoId;
    }
 
源代碼說(shuō)明:
WcmsSystemNewsinfoService類(lèi)的formatRawInfoToHtml(String infoRawId)方法,根據(jù)傳入的參數(shù),準(zhǔn)備好所需的數(shù)據(jù),然后調(diào)用本類(lèi)的saveOrUpdate(WcmsSystemNewsinfoModule module)方法。
saveOrUpdate()方法,根據(jù)情況,調(diào)用WcmsSystemNewsinfoDao類(lèi)的add或者update方法。
 
Spring事務(wù)配置文件
一、事務(wù)配置抽象Bean聲明
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
       <property name="transactionManager" ref="transactionManager"/>
       <property name="transactionAttributes">
           <props>
              <prop key="*">readOnly</prop>
              <prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
              <prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
              <prop key="modify*">PROPAGATION_REQUIRED,-Exception</prop>
              <prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
              <prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>
              <prop key="remove*">PROPAGATION_REQUIRED,-Exception</prop>
              <prop key="query*">PROPAGATION_REQUIRED, readOnly,-Exception</prop>
              <prop key="load*">PROPAGATION_REQUIRED, -Exception</prop>
           </props>
       </property>
    </bean>
 
二、服務(wù)類(lèi)的Spring聲明式事務(wù)管理
<!--
    wcmsSystemNewsinfoService
     -->
    <bean id="wcmsSystemNewsinfoService"
       parent="txProxyTemplate">
       <property name="target">
           <ref bean="wcmsSystemNewsinfoServiceTarget"/>
       </property>
   
    </bean>
 
錯(cuò)誤解析
錯(cuò)誤的原因就在上面的Spring聲明式事務(wù)里。執(zhí)行WcmsSystemNewsinfoService類(lèi)的formatRawInfoToHtml()方法時(shí),會(huì)應(yīng)用txProxyTemplate的配置,由于它的方法名與所有的特殊配置都不匹配,因此,會(huì)應(yīng)用第一個(gè)聲明式事務(wù):
    <prop key="*">readOnly</prop>
因此,SpringAOP創(chuàng)建了一個(gè)只讀的數(shù)據(jù)庫(kù)連接和事務(wù)。
然后,調(diào)用WcmsSystemNewsinfoService類(lèi)的saveOrUpdate()方法,也會(huì)查找上面的事務(wù)配置,匹配:
<prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
SpringAOP會(huì)去得到數(shù)據(jù)庫(kù)連接和設(shè)置事務(wù)。由于在本地線程變量中已經(jīng)找到了前面提供的只讀連接,就會(huì)直接使用這個(gè)數(shù)據(jù)庫(kù)連接,并在其上設(shè)置事務(wù)。
最后,調(diào)用WcmsSystemNewsinfoDao類(lèi)的add方法。由于使用的是只讀連接,執(zhí)行add方法中的update語(yǔ)句,就發(fā)生了上面的錯(cuò)誤:
Caused by:
java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
 
 
Spring真的能夠管理一切嗎?
像上面這樣的Spring事務(wù)配置和Service、Dao的寫(xiě)法,應(yīng)當(dāng)說(shuō)是相當(dāng)普遍的,我們認(rèn)為Spring已經(jīng)把數(shù)據(jù)庫(kù)連接、事務(wù)、O-R映射等等管得妥妥當(dāng)當(dāng)了,不用我們?cè)俨傩牧?,再理解事?wù)了!
真的如此嗎?錯(cuò)!
漠視數(shù)據(jù)庫(kù)、漠視事務(wù),我們的系統(tǒng)到底有多少類(lèi)似的隱患?我們的業(yè)務(wù)服務(wù)類(lèi)Service浪費(fèi)了多少SPringAOP的幫助?降低了多少性能?
Spring、EJB這樣的聲明式事務(wù),確實(shí)大大方便了我們處理數(shù)據(jù)庫(kù)連接和事務(wù)。但是,我們還是需要自己理解業(yè)務(wù)邏輯對(duì)數(shù)據(jù)庫(kù)連接,對(duì)事務(wù)的需要!
工具只能幫助我們解決我們認(rèn)識(shí)到的問(wèn)題,解決不了我們都沒(méi)理解的問(wèn)題。
 
    不能再把一切扔給框架、容器、工具!首先理解你的業(yè)務(wù)邏輯,理解你要實(shí)現(xiàn)的功能,然后搞清楚框架、容器、工具會(huì)幫助我們做什么。只有理解了自己的業(yè)務(wù)邏輯,理解了自己的代碼,理解了自己要用到的第三方代碼,才能真正完美地實(shí)現(xiàn)我們需要的功能!
 
用我們的命名方法來(lái)重構(gòu)上面的問(wèn)題代碼
一、給Service類(lèi)中的2個(gè)方法加上后綴名標(biāo)識(shí)對(duì)事務(wù)的依賴(lài)
    當(dāng)然,Service接口相應(yīng)的方法也要改變。
/* (non-Javadoc)
     * @see com.withub.wcms.manage.collectnews.systemNewsinfo.service.IWcmsSystemNewsinfoService#formatRawInfoToHtml(java.lang.String)
     */
    public String formatRawInfoToHtmlTransaction(String infoRawId) throws Exception{
       WcmsSystemNewsinfoRawModule wcmsSystemNewsinfoRawModule=new WcmsSystemNewsinfoRawModule();
       wcmsSystemNewsinfoRawModule.setInfoId(infoRawId);
       //原表數(shù)據(jù)
        wcmsSystemNewsinfoRawModule=this.getManageNewsinfoService().queryRawInfoById(wcmsSystemNewsinfoRawModule);
   
       WcmsSystemNewsinfoModule wcmsSystemNewsinfoModule=new WcmsSystemNewsinfoModule();
       //目標(biāo)表數(shù)據(jù)
       BeanUtils.copyProperties(wcmsSystemNewsinfoModule, wcmsSystemNewsinfoRawModule);
      
       wcmsSystemNewsinfoModule.setInfoRawId(wcmsSystemNewsinfoRawModule.getInfoId());
       wcmsSystemNewsinfoModule.setInfoId(null);
      
       returnthis.saveOrUpdateDao(wcmsSystemNewsinfoModule);
      
    }
    /**
     *需要把目標(biāo)表Model信息保存在目標(biāo)表中。如果該記錄已存在,則更新,否則,新增!
     *
     *@parammodule
     *@throwsException
     */
    public String saveOrUpdateDao(WcmsSystemNewsinfoModule module) throws Exception{
       WcmsSystemNewsinfoModule loadModule=this.getWcmsSystemNewsinfoDao().selectWcmsSystemNewsinfoModuleByInfoRawId(module.getInfoRawId());
       String infoId=null;
       if(loadModule==null){
           //插入
           infoId=this.getWcmsSystemNewsinfoDao().add(module);
          
       }else{
           //更新
           /**
            *更新
            *1,找到主鍵條件
        */
           infoId=loadModule.getInfoId();
           module.setInfoId(loadModule.getInfoId());
           this.getWcmsSystemNewsinfoDao().updateProcessedInfo(module);
          
       }
       return infoId;
    }
這樣,formatRawInfoToHtmlTransaction方法可以直接被最終用戶(hù)調(diào)用。它將能夠創(chuàng)建或得到數(shù)據(jù)庫(kù)連接,管理事務(wù),最后關(guān)閉數(shù)據(jù)庫(kù)連接。
而,saveOrUpdateDao方法,不能直接被最終用戶(hù)調(diào)用。如果它需要數(shù)據(jù)庫(kù)連接,它可以使用本地線程變量中保存的數(shù)據(jù)庫(kù)連接。
 
二、修改Service類(lèi)的聲明式事務(wù)的配置文件
<!--
    wcmsSystemNewsinfoService
     -->
    <bean id="wcmsSystemNewsinfoService"
       parent="txProxyTemplate">
       <property name="target">
           <ref bean="wcmsSystemNewsinfoServiceTarget"/>
       </property>
       <property name="transactionAttributes">
           <props>
              <prop key="*Transaction">PROPAGATION_REQUIRED,-Exception</prop>
           </props>
       </property>
   
    </bean>
這里,重載了txProxyTemplate的聲明式事務(wù)配置。我們只對(duì)Service類(lèi)中的以Transaction結(jié)尾的方法,應(yīng)用事務(wù),在發(fā)生異常時(shí),回滾。
這樣,Transaction方法直接或者間接調(diào)用的DAO接口中的方法,就可以使用本地線程變量中保存的由Transaction方法的AOP代理方法創(chuàng)建的數(shù)據(jù)庫(kù)連接。
數(shù)據(jù)庫(kù)連接和事務(wù)被真正的擺平了!世界真美好!

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多