spring事务管理(转)_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > spring事务管理(转)

spring事务管理(转)

 2013/7/15 12:16:32  tanzhen-1988  程序员俱乐部  我要评论(0)
  • 摘要:通常通过TransactionProxyFactoryBean设置Spring事务代理。我们需要一个目标对象包装在事务代理中。这个目标对象一般是一个普通Java对象的bean。当我们定义TransactionProxyFactoryBean时,必须提供一个相关的PlatformTransactionManager的引用和事务属性。事务属性含有上面描述的事务定义。<beanid="petStore"class="org.springframework.transaction
  • 标签:Spring
通常通过TransactionProxyFactoryBean设置Spring事务代理。我们需要一个目标对象包装在事务代理中。这个目标对象一般是 一个普通Java对象的bean。当我们定义TransactionProxyFactoryBean时,必须提供一个相关的 PlatformTransactionManager的引用和事务属性事务属性含有上面描述的事务定义。
<bean id="petStore" 
????class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
????<property name="transactionManager"><ref bean="transactionManager"/></property>
????<property name="target"><ref bean="petStoreTarget"/></property>
????<property name="transactionAttributes">
????????<props>
????????????<prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
????????????<prop key="update*">PROPAGATION_REQUIRED</prop>
????????????<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
????????</props>
????</property>
</bean>

事 务代理会实现目标对象的接口:这里是id为petStoreTarget的bean。(使用 CGLIB也可以实现具体类的代理。只要设置proxyTargetClass属性为true就可以。如果目标对象没有实现任何接口,这将自动设置该属性 为true。通常,我们希望面向接口而不是类编程。)使用proxyInterfaces属性来限定事务代理来代 理指定接口也是可以的(一般来说是个好想法)。也可以通过从 org.springframework.aop.framework.ProxyConfig继承或所有AOP代理工厂共享 的属性来定制TransactionProxyFactoryBean的行为。

这里的transactionAttributes属性定义在 org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource 中的属性格式来设置。这个包括通配符的方法名称映射是很直观的。注意 insert*的映射的值包括回滚规则。添加的-MyCheckedException 指定如果方法抛出MyCheckedException或它的子类,事务将 会自动回滚。可以用逗号分隔定义多个回滚规则。-前缀强制回滚,+前缀指定提交(这允许即使抛出unchecked异常时也可以提交事务,当然你自己要明白自己 在做什么)。

TransactionProxyFactoryBean允许你通过 “preInterceptors”和“postInterceptors”属性设置“前”或“后”通知来提供额外的 拦截行为。可以设置任意数量的“前”和“后”通知,它们的类型可以是 Advisor(可以包含一个切入点), MethodInterceptor或被当前Spring配置支持的通知类型 (例如ThrowAdviceAfterReturningtAdviceBeforeAdvice, 这些都是默认支持的)。这些通知必须支持实例共享模式。如果你需要高级AOP特 性来使用事务,如有状态的maxin,那最好使用通用的 org.springframework.aop.framework.ProxyFactoryBean, 而不是TransactionProxyFactoryBean实用代理创建者。

也可以设置自动代理:配置AOP框架,不需要单独的代理定义类就可以生成类的 代理。

附两个spring的事务配置例子
<prop key="add">
???? PROPAGATION_REQUIRES_NEW, -MyException
</prop>
注:上面的意思是add方法将独占一个事务,当事务处理过程中产生MyException异常或者该异常的子类将回滚该事务。

<prop key="loadAll">
????PROPAGATION_SUPPORTS, ISOLATION_READ_COMMITED, Readonly
</prop>
注:表示loadAll方法支持事务,而且不会读取没有提交事务的数据。它的数据为只读(这样有助于提高读取的性能)

附A Spring中的所有事务策略

PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED_NEW
PROPAGATION_SUPPORTS

附B Spring中所有的隔离策略:

ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITED
ISOLATION_COMMITED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE

Spring事务类型祥解

大家可能在spring中经常看到这样的定义:

?

<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop><prop key="store*">PROPAGATION_REQUIRED</prop>

估计有好多朋友还没有弄清楚里面的值的意思,仔细看完下面应该知道自己什么情况下面应该使用什么样的声明。^_^

?

Spring中常用事务类型:

  • PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
  • PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
摘要:
Spring 和EJB一样,提供了两种事务管理方式:编程式和声明式。在考试系统中我们将使用声明式的事务管理,这是spring推荐的做法。使用这种方式可以体验到 spring的强大便捷,而且我们无须在Dao类中编写任何特殊的代码,只需要通过配置文件就可以让普通的java类加载到事务管理中,这个意义是很重大 的。


本文Matrix永久镜像:http://www.matrix.org.cn/resource/article/1/1339.html
说明:本文可能由Matrix原创,也可能由Matrix的会员整理,或者由
Matrix的Crawler在全球知名Java或者其他技术相关站点抓取并永久
保留镜像,Matrix会保留所有原来的出处URL,并在显著地方作出说明,
如果你发觉出处URL有误,请联系Matrix改正. 四、Spring中的事务控制

Spring 和EJB一样,提供了两种事务管理方式:编程式和声明式。在考试系统中我们将使用声明式的事务管理,这是spring推荐的做法。使用这种方式可以体验到 spring的强大便捷,而且我们无须在Dao类中编写任何特殊的代码,只需要通过配置文件就可以让普通的java类加载到事务管理中,这个意义是很重大 的。

Spring中进行事务管理的通常方式是利用AOP(面向切片编程)的方式,为普通java类封装事务控制,它是通过动态代理实现 的,由于接口是延迟实例化的,spring在这段时间内通过拦截器,加载事务切片。原理就是这样,具体细节请参考jdk中有关动态代理的文档。本文主要讲 解如何在spring中进行事务控制。

动态代理的一个重要特征是,它是针对接口的,所以我们的dao要通过动态代理来让spring接管事务,就必须在dao前面抽象出一个接口,当然如果没有这样的接口,那么spring会使用CGLIB来解决问题,但这不是spring推荐的方式,我们也不做讨论。

参照前面的例子,我们为StudentManager.java定义一个接口,它的内容如下:

/*
 * 创建日期 2005-3-25
 */
package org.bromon.spring.examer.student;

import java.util.List;

import org.bromon.spring.examer.pojo.Student;

/**
 * @author Bromon
 */
public interface StudentManagerInterface
{
? ? public void add(Student s);
? ? public void del(Student s);
? ? public void update(Student s);
? ? 
? ? public List loadAll();
? ? public Student loadById(int id);
}

StudentManager也应该做出修改,实现该接口:

public class StudentManager extends HibernateDaoSupport implements StudentManagerInterface

现 在需要修改配置文件,用于定义Hibrenate适用的事务管理器,并且把sessionFactory注入进去,同时还需要通过注册一个 DefaultTransactionAttribute对象,来指出事务策略。其中sessionFactory的定义已经在本文的第三章中说明。

首先定义一个Hibernate的事务管理器,让它来管理sessionFactory:
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
? ?? ?<property name="sessionFactory">
? ?? ?? ?<ref bean="sessionFactory"/>
? ?? ?</property>
</bean>

下面定义事务管理策略,我们希望把策略定义在方法这个级别上,提供最大的灵活性,本例中将add方法定义为:PROPAGATION_REQUIRES_NEW,这可以保证它将始终运行在一个事务中。

<bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
? ?? ?<property name="properties">
? ?? ?? ?<props>
? ?? ?? ?? ?<prop key="add">
? ?? ?? ?? ?? ?PROPAGATION_REQUIRES_NEW
? ?? ?? ?? ?</prop>
? ?? ?? ?</props>
? ?? ?</property>
? ?</bean>

我们不仅可以为add方法定义事务策略,还可以定义事务隔离程度和回滚策略,他们以逗号隔开,比如我们的add事务可以定义为:

<prop key="add">
? ?PROPAGATION_REQUIRES_NEW,-ExamerException
</prop
>

这个事务策略表示add方法将会独占一个事务,当事务过程中产生ExamerException异常,事务会回滚。

Add/update/del都是写入方法,对于select(读取)方法,我们可以指定较为复杂的事务策略,比如对于loadAll()方法:

<prop key=”loadAll”>
? ?? ?PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITED,readOnly
? ?</prop>


该事务的含义为,loadAll方法支持事务,不会读去位提交的数据,它的数据为只读(可提高执行速度)。

如 你所见,我们的StudentManagerInterface接口中还有一个loadById(int id)方法,也许我们将来还会有很多的loadByXXXX的方法,难道要意义为他们指定事务策略?太烦人了,他们应该和loadAll()一样,所以我 们可以使用通配符,定义所有的loadXXXX方法:

<prop key=”load*”>
? ?? ?PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITED,readOnly
? ?</prop>


现在可以定义事务管理器:
<bean id="studentManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
? ?? ?<property name="target">
? ?? ?? ?<ref bean="studentManager"/>
? ?? ?</property>
? ?? ?<property name="transactionManager">
? ?? ?? ?<ref bean="transactionManager"/>
? ?? ?</property>
? ?? ?<property name="transactionAttributeSource">
? ?? ?? ?<ref bean="transactionAttributeSource"/>
? ?? ?</property>
</bean>


这 个bean的外观是一个接口(StudentManagerInterface),我们指出了它的具体实现(studentManager),而且为它绑 定了事务策略。在客户端使用的时候,获得对象是StudentManagerInterface,所有的操作都是针对这个接口的。测试代码并没有改变,我 们虽然修改了很多地方,加入了事务控制,但是客户端并没有受到影响,这也体现了spring的一些优势。测试代码如下:

public void testAdd() 
? ? {
? ? ? ? ApplicationContext ctx=new ClassPathXmlApplicationContext("springConfig.xml");
? ? ? ? StudentManager sm=(StudentManager)ctx.getBean("studentManager");
? ? ? ? 
? ? ? ? Student s=new Student();
? ? ? ? s.setId(1);
? ? ? ? s.setName("bromon");
? ? ? ? s.setPassword("123");
? ? ? ? s.setGrade(1);
? ? ? ? s.setSex(0);
? ? ? ? 
? ? ? ? sm.add(s);
}


通过以上的代码可以看出,spring可以简单的把普通的java class纳入事务管理,声明性的事务操作起来也很容易。有了spring之后,声明性事务不再是EJB独有,我们不必为了获得声明性事务的功能而去忍受EJB带来的种种不便。

我所使用的mysql是不支持事务的,你可以更换使用PostgreSQL,有了spring+hibernate,更换db并不像以前那样恐怖了,步骤很简单:

1、 添加PostgreSQL的jdbc驱动
2、 修改dataSource配置,包括驱动名称、url、帐号、密码
3、 修改sessionFactory的数据库dailet为net.sf.hibernate.dialect.PostgreSQLDialect
4、 修改hbm.xml中的主键生成策略为increment

所有的修改都在配置文件中完成,业务代码不需要任何修改,我很满意,How about u?

?

??????????????????????????

spring声明式事务管理的两种方式

传统的:
?1?<bean?id="dataSource"?class="org.apache.commons.dbcp.BasicDataSource"?destroy-method="close">
?2?????????<property?name="driverClassName"?value="oracle.jdbc.driver.OracleDriver"?/>
?3?????????<property?name="url"?value="jdbc:oracle:thin:@127.0.0.1:1521:dev"?/>
?4?????????<property?name="username"?value="kaktos"?/>
?5?????????<property?name="password"?value="kaktos"?/>
?6?????</bean>
?7?
?8?????<bean?id="txManager"
?9?????????class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
10?????????<property?name="dataSource"?ref="dataSource"?/>
11?????</bean>
12?
13?????<bean?id="businessBean"
14?????????class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
15?????????<property?name="transactionManager"?ref="txManager"?/>
16?????????<property?name="target"?ref="businessBeanTarget"?/>
17?????????<property?name="transactionAttributes">
18?????????????<props>????????????????
19?????????????????<prop?key="*">PROPAGATION_REQUIRED</prop>
20?????????????</props>
21?????????</property>
22?????</bean>
23?????
24?????<bean?id="businessBeanTarget"?class="sample.spring.trans.BusinessBean">
25?????????<property?name="dataSource"?ref="dataSource"?/>
26?????</bean>

这样做的弊端就是不得不为每个需要事务的bean做一次声明,如果所有的bean都基本上有一致的配置,这样就太繁琐啦。
下面是第二种方式:
?1?<beans>
?2?????<bean?id="dataSource"?class="org.apache.commons.dbcp.BasicDataSource"?destroy-method="close">
?3?????????<property?name="driverClassName"?value="oracle.jdbc.driver.OracleDriver"?/>
?4?????????<property?name="url"?value="jdbc:oracle:thin:@127.0.0.1:1521:dev"?/>
?5?????????<property?name="username"?value="kaktos"?/>
?6?????????<property?name="password"?value="kaktos"?/>
?7?????</bean>
?8?
?9?????<bean?id="txManager"
10?????????class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
11?????????<property?name="dataSource"?ref="dataSource"?/>
12?????</bean>
13?
14?????<bean?id="matchAllWithPropReq"
15?????????class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
16?????????<property?name="transactionAttribute"?value="PROPAGATION_REQUIRED"?/>
17?????</bean>
18?????
19?????<bean?id="matchAllTxInterceptor"?class="org.springframework.transaction.interceptor.TransactionInterceptor">
20?????????<property?name="transactionManager"?ref="txManager"?/>
21?????????<property?name="transactionAttributeSource"?ref="matchAllWithPropReq"?/>
22?????</bean>
23?
24?????<bean?id="autoProxyCreator"
25?????????class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
26?????????<property?name="interceptorNames">
27?????????????<list>
28?????????????????<idref?local="matchAllTxInterceptor"?/>
29?????????????</list>
30?????????</property>
31?????????<property?name="beanNames">
32?????????????<list>
33?????????????????<idref?local="businessBean"?/>
34?????????????</list>
35?????????</property>
36?????</bean>
37?????
38?????<!--??my?beans??-->
39?????<bean?id="businessBean"?class="sample.spring.trans.BusinessBean">
40?????????<property?name="dataSource"?ref="dataSource"?/>
41?????</bean>
42?</beans>

BeanNameAutoProxyCreator会在applicationcontext初始化后自动为beanNames属性中的bean建立proxy。 ? 转自:http://www.blogjava.net/baoyaer/articles/93060.html

?

发表评论
用户名: 匿名