1.2 spring 事務

例1:springMVC 統一處理service異常回滾:(注這種聲明式(配置或者註解)在springMVC中有可能實現,見例1.1)
xml:
   <!-- 定義切面,進行過濾,添加service的方法在事務控制範圍。  -->
<aop:config proxy-target-class="true">

<aop:pointcut id="allManagerMethod" expression="execution(* com..*.services.*Service.*(..))" />

<!--com..*表示com包及com包下所有子包;.*Service.*(..)表示以Service結尾的類下的所有方法-->

<aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod" /> 
</aop:config>
 
<!-- 基本事務定義,使用transactionManager作事務管理,默認get* find*方法的事務爲readonly,其餘方法按默認設置. 默認的設置請參考Spring文檔事務一章. -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="find*" read-only="true"/>
<tx:method name="get*"  read-only="true"/>
<tx:method name="qry*"  read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="load*" read-only="true"/>
<tx:method name="*" />
</tx:attributes>
</tx:advice>

  <!--  啓動加載異常處理的類,用於監聽各模塊中觸發的異常  -->
    <bean id="handlerExceptionResolver" class="com.core.exception.MyHandlerExceptionResolver">
    <property name="defaultErrorView" value="commons/defaultError"/>
    </bean>


HandlerExceptionResolver的實現:
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {

private Logger logger = LoggerFactory.getLogger(getClass());
private String defaultErrorView;
public String getDefaultErrorView() {
return defaultErrorView;
}
public void setDefaultErrorView(String defaultErrorView) {
this.defaultErrorView = defaultErrorView;
}
@SuppressWarnings("unchecked")
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
logger.error("class = "+handler.getClass());
logger.error("exception = "+ex.getClass());
logger.error("exception = "+ex.getCause());
logger.error("Handle exception: " + ex.getMessage());
Map model = new HashMap();
model.put("ex", ex.getClass().getSimpleName());
model.put("error", ex.getClass()+"<br>"+ex.toString());
return new ModelAndView(defaultErrorView, model);
}
}

注:只可以對unchecked 異常進行回滾(service中不用再添加try快)。對於其他的異常不會進行回滾。不過你也可以通過rollback-for屬性進行指定你所要拋出的異常類型。


例1.1:springMVC 經典事務失效問題(applicationContext.xml和springmvc-servlet.xml配置問題)

a.在主容器中(applicationContext.xml),將Controller的註解排除掉 
<context:component-scan base-package="com"> 
  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> 
</context:component-scan> 
而在springMVC配置文件中將Service註解給去掉 
<context:component-scan base-package="com"> 
  <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> 
  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> 
  </context:component-scan> 
b.參考文章
http://icanfly.iteye.com/blog/778401(good)
http://hi.baidu.com/wangbeiyong/item/e73728e5644e1d0d64db0079
http://hi.baidu.com/wangbeiyong/item/e73728e5644e1d0d64db0079


----------------------------

例二:看看一個ssh項目中的事務配置例子:
xml:事務配置:
<!-- 定義事務管理器(聲明式的事務) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事務屬性 -->
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED</prop>
<prop key="load*">PROPAGATION_REQUIRED</prop>
<prop key="query*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="create*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="put*">PROPAGATION_REQUIRED</prop>
<prop key="check*">PROPAGATION_REQUIRED</prop>
<prop key="apply*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
<bean id="entityDao" class="com.test.dao.impl.EntityDaoImpl">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
注意:PROPAGATION_REQUIRED:如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。這是最常見的選擇。
如上面的配置,就能確保Service中每個方法中的內容在同一個事務中,這些內容有可能有其他的方法,如同下邊A2中所有內容在一個事務中,不管是否含有A1


一。
action:
public void a() {

aService.createA2("111",auth);

}

services:
1.//測試一下:services中單個方法拋出異常,會發生回滾
此時事務全在A2中,
    @Override
    public String createA2(String str, Authorization auth){
//this.createA1("11",auth);

TermShop termshop=new TermShop();
termshop.setSerialNo("12");
this.createTermShop(termshop, auth);

TermShop termshop2=new TermShop();
termshop2.setSerialNo("12");
this.createTermShop(termshop2, auth);
if(1==1){
   throw new RuntimeException();
}
return "aaa";

}

2.//測試一下:services中一個方法調用另一個方法,拋出異常,這個事務不會提交,會發生回滾
此時因爲配置中service有事務控制,首先在A2中創建事務,當調用A1的時候,因爲A2中已經有一個事務,所以不需要重新在A1中創建事務,共用A2創建的事務。(即爲A2中所有共用一個事務)
    @Override
    public String createA1(String str, Authorization auth){
TermShop termshop=new TermShop();
termshop.setSerialNo(str);
this.createTermShop(termshop, auth);
return "-----aaa-----";
    }
    
    
    @Override
    public String createA2(String str, Authorization auth){
System.out.println(this.createA1("12",auth));

TermShop termshop=new TermShop();
termshop.setSerialNo("12");
this.createTermShop(termshop, auth);


TermShop termshop2=new TermShop();
termshop2.setSerialNo("12");
this.createTermShop(termshop2, auth);
if(1==1){
   throw new RuntimeException();
}
return "aaa";

}
   
二。    
如果action中這樣調用,因爲配置事務在services中,此時有兩個事務,一個控制A1,一個控制A2
1.如果action中不捕獲異常,因爲A1發生異常,導致程序中斷,所以也不會存入數據。
2.如果action中捕獲異常,如下,則當A1發生異常,程序照樣運行,A2中會存入數據 (原因:因爲爲exception的時候,spring異常沒法捕獲,所以解決方法不用try catch,或者catch的異常爲RunException或者DataAccessException,而不是 exception) 

public void a() {
try {
   aService.createA1("111",auth);
} catch (Exception e) {
 e.printStackTrace();
}
aService.createA2("111",auth);

}

services:
    @Override
    public String createA1(String str, Authorization auth){
TermShop termshop=new TermShop();
termshop.setSerialNo("12");
this.createTermShop(termshop, auth);
if(1==1){
  throw new RuntimeException();
}
return "-----aaa-----";
    }
        
    @Override
    public String createA2(String str, Authorization auth){

TermShop termshop=new TermShop();
termshop.setSerialNo("12");
this.createTermShop(termshop, auth);

TermShop termshop2=new TermShop();
termshop2.setSerialNo("12");
this.createTermShop(termshop2, auth);
if(1==1){
  // throw new RuntimeException();
}
return "aaa";

}



    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章