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";
}