在http://gary-bu.iteye.com/blog/2024022 中我们了解了如何配置一个springmvc,如何在spring配置文件中配置一个dbcp数据源,在web.xml配置上下文监听器,分发器,视图解析器等,而这篇主要看一下如何在上次的基础上配置事务.
spring事务分声明式事务和编程式事务,我们今天主要说一下声明式事务,spirng的事务是通过AOP代理实现的,其中的事务通知 由原数据(目前基于XML或者注解)驱动.代理对象与事务元数据结合产生了一个AOP代理,它使用一个PlatformTransactionManager实现 配合TransactionInterceptor在方法调用前后实施事务.
第一种实现,基于XML的配置:
基于jdbc连接,所以需要配置一个DataSourceTransactionManager,然后指定数据源
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="jdbcDataSource" />
配置事务通知,指定transactionManager,设定所有方法都走事务,并且get开头的方法只读,我们来看几个关键属性,
1.propagation:事务传播,取值
REQUIRED:为每一个被应用的方法创建一个逻辑事务作用域.
REQUIRES_NEW:为每一个相关的作用域使用一个完全独立的事务,在这种情况下物理事务也是不同的因此外部事务可以不受内部事务回滚的影响独立提交或回滚.
SUPPORTS:如果存在一个事务, 支持当前事务. 如果没有事务, 则非事务的执行
NOT_SUPPORTED:总是非事务地执行, 并挂起任何存在的事务
NEVER:总是非事务地执行, 如果存在一个活动事务, 则抛出异常
NESTED:使用了单独的物理事务,这个事务拥有多个可以回滚的保存点,这样部分会滚允许内部事务在它的作用域内触发一个回滚,并且外部事务可以不受影响继续,这通常对应于JDBC的保存点,所以
只在JDBC 资源管理事务管理上起效.
MANDATORY:如果已经存在一个事务, 支持当前事务. 如果没有一个活动的事务, 则抛出异常.
2.get方法设置read-only,因此数据库将会为只读事务提供一些优化手段.
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
AOP配置:
配置切入点,切入点表达式详情请参考http://blog.csdn.net/archie2010/article/details/6254343
配置advisor ,指定事务通知,指定切入点
<aop:config>
<!-- 切入点表达式 -->
<aop:pointcut id="txPointcut" expression="excution(* com.xg.myspring.service..*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
现在基于XML的事务配置就完成了,在编写方法的时候注意命名规则就好了
注意需要在lib中添加aspectweaver.jar包
第二种实现,基于注解
这种配置相对简单,但是要在代码中进行注解
配置代码,只需要在注解驱动中指定事务管理
<!-- 注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
然后就是在代码中添加注解,举个例子:
package com.xg.myspring.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.xg.myspring.dao.SystemUserDao;
import com.xg.myspring.entity.SystemUser;
import com.xg.myspring.service.SystemUserService;
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class SystemUserServiceImpl implements SystemUserService {
@Resource
private SystemUserDao systemUserDao;
public List<SystemUser> queryUserList(String sql) {
systemUserDao.addSystemUser(new SystemUser());
if (2 > 1) {
throw new NullPointerException();
}
return systemUserDao.queryUserList(sql);
}
}
上面的代码中,注意看红色部分,给整个类下所有方法添加了REQUIRED的事务,然后故意在queryUserList方法中抛出异常,查看事务执行情况,数据是不会提交的.
当然你也可以把事务注解添加在方法上.
项目运行时报异常在所难免,spring提供了异常处理机制,来增加我们界面的友好性.接下来,我们看一下如何配置
<!-- 异常处理 -->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.Exception">errors/error</prop>
</props>
</property>
<property name="defaultErrorView" value="errors/error"></property>
<!-- 处理异常后打印日志 -->
<property name="warnLogCategory" value="ERROR"></property>
</bean>
说明:
1、defaultErrorView, 当没有配置异常处理映射时,该默认视图将起作用
2、exceptionMappings 异常处理映射Property,key=“异常名称”, vlaue=异常处理视图
3、warnLogCategory 捕获异常后打印异常日志
另外对于Unchecked Exception 由于代码不强制捕获,往往被忽略,如果运行期产生了Unchecked Exception,就会出现404、500……等服务器内部错误提示页面。
目前大多数服务器也都支持在web.xml中通过<error-page>指定异常情况的显示页面。修改web.xml文件,增加以下内容:
<!-- 对Unchecked 异常处理 -->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/page/errors/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/page/errors/error_404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/page/errors/error_500.jsp</location>
</error-page>
我们可以模拟一下404错误,在进行页面跳转的时候把页面写错,这样通过上述配置就可以成功跳转到我们预设的404页面了.
这样异常处理就完整了,附件更新了demo代码,文章讲的不清楚的地方可以下载看看.
那天看到有人在讨论,在事务回滚的时候想添加一下日志信息,结果却添加不进去因为一起回滚了,看了一下资料,好像需要对事务做一些配置,想亲自实践一下,就在下篇文章记录一下吧.