在Spring中实现声明控制的事务管理3Eclipse.docx
《在Spring中实现声明控制的事务管理3Eclipse.docx》由会员分享,可在线阅读,更多相关《在Spring中实现声明控制的事务管理3Eclipse.docx(22页珍藏版)》请在冰豆网上搜索。
在Spring中实现声明控制的事务管理3Eclipse
在Eclipse中实现Spring中声明控制的事务管理
1、实现Spring的声明控制的事务管理
(1)声明控制的事务管理的实现----借助于SpringIoC和AOP
Spring提供声明控制的事务管理,这是借助于SpringIoC和AOP所提供的功能,同时提供了TransactionInterceptor拦截器和常用的代理类TransactionProxyFactoryBean,可以直接对组件进行事务代理。
(2)尽量使用声明控制的事务管理
不过现在我们不必太理会SpringAOP的编程实现,而只需要进行基本的配置,我们就可以使用声明控制的事务管理。
建议在基于SpringFramework的应用开发中,尽量使用声明控制的事务管理,以获得数据逻辑代码的最佳可读性。
(3)所需要的*.jar包文件---应该加入到系统中
Spring的事务管理依赖于aopalliance.jar与cglib-nodep-2.1_3.jar。
因此,我们必须在Web应用的lib目录下增加对aopalliance.jar(在spring-framework-1.2.6\lib\aopalliance目录内)与
对cglib-nodep-2.1_3.jar的引用(在spring-framework-1.2.6\lib\cglib目录内)。
将它们加入到我们的lib目录中
(4)优点----实现类似EJBCMT的特性
使用声明控制的事务管理的好处是,事务管理不侵入我们所开发的组件(此时,在DAO类中不再需要对TransactionManager类的对象的引入),具体来说,我们的DAO类不会意识到正在事务管理之中,而且如果我们想要改变事务管理的策略的话,也只需要在定义配置文件中重新组织即可。
2、实现的基本原理
Spring中进行事务管理的通常方式是利用AOP(面向切片编程)的方式,为普通Java类封装事务控制,它是通过动态代理实现的,由于接口是延迟实例化的,Spring在这段时间内通过其拦截器来加载事务管理器。
3、实现的主要形式
(1)面向目标接口
动态代理的一个重要特征是,它是针对接口的,所以我们的DAO要通过动态代理来让Spring接管事务,就必须在DAO前面抽象出一个接口并面向该目标接口。
(2)面向目标实现类
当然如果没有这样的目标接口,那么Spring会使用CGLIB来解决问题,但这不是Spring所推荐的方式(此时应该设置proxyTargetClass属性为true)。
4、TransactionProxyFactoryBean类----作为DAO组件的事务代理组件
(1)作用
要进行声明控制的事务管理,一个简化的方法是使用TransactionProxyFactoryBean组件,通过它可以指定要介入的事务管理对象及其方法。
(2)定义
(3)应用的要求
TransactionProxyFactoryBean需要一个transactionManager属性,由于我们直接使用JDBC,所以在下面的示例中继续使用DataSourceTransactionManager类。
同时还需要target属性,该属性定义需要进行事务代理的类---也就是我们的DAO组件类
最后,还需要一个transactionAttributes属性,定义具体的事务要求。
在Eclipse中实现本例中的声明式的事务管理的过程
Spring声明式事务处理中由于主要使用了IoC和AOP思想,同时提供了TransactionInterceptor拦截器和常用的代理类TransactionProxyFactoryBean,从而可以允许开发者直接以配置的方式实现对组件进行事务代理。
注意:
下面的具体实现过程是在前面的代码方式的过程的基础上进行的。
因此,省略了前面的表示层和控制层的代码的实现过程的说明------具体,可以看前面的代码方式的过程。
1、添加*.jar包文件到本项目中
最后为下面的状态
2、具体的实现过程----在springapp-servlet.xml文件中再增加下面的配置
(1)添加transactionManager的配置
(2)添加一个TransactionProxyFactoryBean的对象声明
com.px1987.springwebapp.dao.DAOInterface
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED,readOnly
对上面的各个标签的说明:
●TransactionProxyFactoryBean是个代理类,其target属性指定要代理的对象(daoImpleProxy节点配置了一个针对daoImpleObject的事务代理),事务管理会自动地介入指定的方法前后。
由于工程大部分的类都要数据库操作,如果每次都要实例化这个bean(“daoImpleProxy”这个bean)的话,会非常消耗资源的----Spring默认都是被管理的对象都是单例的。
●proxyInterfaces:
代理类应该实现的接口列表
●这里,我们通过transactionAttributes属性指定了事务的管理策略,updateOneUserInfo*表示指定方法名称updateOneUserInfo开头的都要納入事务管理,我们也可以指定方法的全名,如果在方法执行过程中发生了错误(抛出异常),則所有操作自动撤回,否則正常提交。
●updateOneUserInf*等方法上指定了PROPAGATION_REQUIRED,表示在目前的事务中执行操作,如果事务不存在就建立一个新的,相关的常量的含义都可以在API文件中TransactionDefinition接口中找到。
另一方面,对于其他方法(通过通配符*表示),则进行只读事务管理,以获得更好的性能----不会读取未提交的数据,同时它的数据为只读(可提高执行速度)----如可以避免对脏数据的检查。
PROPAGATION_REQUIRED,readOnly
注意:
Spring的事务属性支持一个称为“回滚规则”的概念
默认情况下,任何RuntimeException或Error的抛出均会导致回滚。
当然,我们也可以加上多个事务的定义,中间使用逗号","隔离开,例如我们可以加上只读,或者是指定某个异常产生时(并告诉事务代理,在抛出该异常时执行进行回滚),执行回滚操作。
PROPAGATION_REQUIRED,readOnly,-ExamerException
上面的这个事务策略表示某个方法将需要一个事务支持,同时当在事务过程中,如果产生了ExamerException异常,事务将会回滚。
在MyCheckedException前面加上“-”時,表示产生指定的异常时撤消操作,如果前面加上"+",表示产生指定的异常时立即提交。
下面列出事务属性各个参数的含义
●PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。
这是最常见的选择。
PROPAGATION_REQUIRED等同于EJB中的TX_REQUIRED
其实现的策略为
如果我们希望服务方法一直在事务中运行,就可以使用PROPAGATION_REQUIRED。
我们使用PROPAGATION_REQUIRED的时候,如果某个TX已经在运行中,那么bean方法加入那个TX,否则Spring轻量级TX管理器将为你重新启动一个。
●PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
●PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
●PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起---这可以保证它将始终运行在一个事务中。
PROPAGATION_REQUIRES_NEW等同于EJB中的TX_REQUIRES_NEW
其实现的策略为
如果我们希望在组件服务被调用的时候,一般情况下启动新事务,那么就可以使用PROPAGATION_REQUIRES_NEW属性了。
●PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
●PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
●PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。
如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
前六个策略类似于EJBCMT中的常量名相同(请见下面的EJB中的事务的属性说明),因此,对EJB开发人员来说,应该立刻就感到熟悉。
第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
它要求事务管理器或者使用JDBC3.0SavepointAPI提供嵌套事务行为(如Spring的DataSourceTransactionManager),或者通过JTA支持嵌套事务。
注意:
EJB中的事务的属性说明
●Nerver:
不参与事务,如果参与产生RemoteException
●NotSupported:
不能参与
●Supports:
如果调用者正在参与事务,相应的EJB调用也可以参与事务,否则不能
●Mandatory如果调用者有一个事务,相应的EJB可以参与事务,否则,TransactionRequiredException
●Required如果调用者有一个事务,相应的EJB可以参与事务,否则,容器将在调用相应的EJB之前,开始一个事务。
●当方法调用完成以后,即提交该事务。
●RequiresNew在调用相应的EJB之前,开始一个新的事务,当方法调用返回时,即提交这个事务。
注意:
嵌套事务类型(PROPAGATION_NESTED),是相对上面提到的六种情况(上面的六种应该称为平面事务类型),打个比方我现在有一个事务主要有一下几部分:
●从A用户帐户里面减去100元钱
●往B用户帐户里面添加100元钱
这样看和以前不同的事务可能没有什么区别,那我现在有点特殊的要求就是,A用户有3个帐户,B用户有2个帐户,现在我的要求就是只要再A用户的3个帐户里面任意一个减去100元,往B用户的两个帐户中任意一个里面增加100元就可以了!
一旦我们有这样的要求,那嵌套事务类型就非常适合我们的需要!
我们可以这样理解:
●将“从A用户帐户里面减去100元钱”和“往B用户帐户里面增加100元钱”我们暂时认为是一级事务操作
●将从A用户的3个帐户的任意一个帐户里面减钱看做是“从A用户帐户里面减去100元钱”这个一级事务的子事务(二级事务),同样把后面存钱的看成是另一个的二级事务。
(3)完整的配置内容为下面的状态
xmlversion="1.0"encoding="UTF-8"?
>
DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN2.0//EN"
"http:
//www.springframework.org/dtd/spring-beans-2.0.dtd">
showResult
springappController
userLoginController
userLoginController
userLoginController
org.springframework.web.servlet.view.InternalResourceView
/
.jsp
showOtherError
showDBError
showRuntimeError
net.sourceforge.jtds.jdbc.Driver
jdbc:
jtds:
sqlserver:
//localhost:
1433/WebStudyDB
sa
1234
com.px1987.springwebapp.dao.DAOInterface
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED,readOnly
3、在UserManageImple类中获得daoImpleProxy,并将它转换为DAOInterface类的对象----只需要在userManager.xml中做下面的配置修改。
4、在DAOImple类中不需要做任何附加编程
packagecom.px1987.springwebapp.dao;
importcom.px1987.springwebapp.model.UserInfoVO;
importorg.springframework.jdbc.core.*;
importjava.util.*;
publicclassDAOImpleimplementsDAOInterface
{
JdbcTemplatejdbcTemplate=null;
publicDAOImple()
{
//TODO自动生成构造函数存根
}
publicbooleandeleteOneUserInfo(intuserID)
{
//TODO自动生成方法存根
returnfalse;
}
publicbooleaninsertOneUserInfo(UserInfoVOoneUserInfoVO)
{
StringinsertStatement="insertintoUserInfovalues(?
?
?
?
?
?
?
?
)";
java.util.Datenow=newjava.util.Date();
ObjectuserInfoParameter[]={
oneUserInfoVO.getUserName(),
oneUserInfoVO.getUserPassWord(),
oneUserInfoVO.getUserDepartment(),
newInteger(oneUserInfoVO.getUserAdminLevel()),
newInteger(oneUserInfoVO.get