Spring --- Transaction Management

一)spring的事务管理
事务管理并非spring独有,用过JDBC hibernate的朋友都知道,这些api和框架都提供了自己的事务管理机制。那么spring的事务管理又有些什么与众不同支持呢?它的优点又有哪些呢?总结来说大概有以下这么几点:
1' 为不同的事务API提供一致的编程模型,如Java Transaction API (JTA)、JDBC、Hibernate、JavaPersistenceAPI(JPA)以及JavaDataObjects(JDO)
2' 支持declarative transaction management(声明式事务管理)
3' 为一些原本比较复杂的事务API提供简化的programmatic transaction management(编程式事务管理)API
4' 出色的整合Spring数据访问抽象
学习spring的事务管理的过程其实也就是通过例子理解以上4大优点的过程。所以下面,我们就结合实际的例子来慢慢分析这些优点吧 ^.^

二)整合Spring数据访问抽象
[b]JDBC[/b]
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

它使用的是transaction manager类是:DataSourceTransactionManager。此外还定义了jdbc datasource。

[b]JTA[/b]
如果你datasource使用的是JNDI技术,并且通过JTA的API来进行事务管理,那么你的配置将会是这样:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

它对应的transaction mangager类是:JtaTransactionManager

[b]Hibernate[/b]
如果你使用过hibernate,你就知道hibernate中的sessionFactory对象是其核心控制类。它掌管着orm转换、连接配置、日志格式等众多属性配置。spring则在此基础上再做了一层封装以用于事务管理。所以配置样式如下:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>hibernate.dialect=${hibernate.dialect}</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

这里的datasource bean的配置和上面JDBC的例子中的一样,故这里就不再重复列出了。这里的transaction mangager类是HibernateTransactionManager

总结来说:当我们使用JDBC时,我们调用的是DataSourceTransactionManager;当我们使用JTA时,我们调用的是JtaTransactionManager;而当我们使用Hibernate时,我们调用的是HibernateTransactionManager...其实,spring的事务管理,不论你最终采用哪种技术,[b]它都是接口PlatformTransactionManager的一种实现。[/b]如果你进一步研究一下PlatformTransactionManager接口,你就会明白spring是如何将众多数据访问方法抽象统一的了:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}

这里需要重点说明的是getTransaction(..)方法。它根据传入的TransactionDefinition类(它携带Isolation Propagation Timeout Read-only status等信息)来返回一个TransactionStatus类来代表新的一个事务或已存在的事务。有了这些接口,你完全可以自定义自己的transaction manager类。但还是那句话,绝大多数情况下,我们不需要这么做。spring已经为我们准备好了足够丰富的transaction manager类。

三)声明式事务管理
依赖于spring AOP。我们举例说明,假设我们需要对接口FooService下所有类进行事务管理:
// the service interface that we want to make transactional
package x.y.service;
public interface FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}

// an implementation of the above interface
package x.y.service;
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
throw new UnsupportedOperationException();
}
public Foo getFoo(String fooName, String barName) {
throw new UnsupportedOperationException();
}
public void insertFoo(Foo foo) {
throw new UnsupportedOperationException();
}
public void updateFoo(Foo foo) {
throw new UnsupportedOperationException();
}
}

那么我们可以配置如下:
<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>

<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution of an operation defined by the FooService interface -->
<aop:config>
<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>

<!-- don't forget the DataSource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
<!-- similarly, don't forget the PlatformTransactionManager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- other <bean/> definitions here -->
</beans>

对于回滚事务,我们可以指定:
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

上例显示的指出,对于NoProductInStockException,我们做回滚处理。此外<tx:method/>可以对propagation isolation做相应的设定。

四)编程式事务管理
如果你要使用编程式的事务管理(适合少量需要事务管理的情形)。那么两个类可供你选择使用:TransactionTemplate 和 PlatformTransactionManager
1' TransactionTemplate
先是有返回值的情况:
public class SimpleService implements Service {
// single TransactionTemplate shared amongst all methods in this instance
private final TransactionTemplate transactionTemplate;
// use constructor-injection to supply the PlatformTransactionManager
public SimpleService(PlatformTransactionManager transactionManager) {
Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
// the code in this method executes in a transactional context
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}

无返回值的情况:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessExeption ex) {
status.setRollbackOnly();//代码显示的强行进行rollback
}
}
});

还可以进行一些属性的设置:
public class SimpleService implements Service {
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");
this.transactionTemplate = new TransactionTemplate(transactionManager);
// the transaction settings can be set here explicitly if so desired
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30); // 30 seconds
// and so forth...
}
}


2' PlatformTransactionManager
有之前声明式事务管理的介绍,相信将PlatformTransactionManager转换为编程式的事务管理就简单了:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// execute your business logic here
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);


五) propagation和isolation
1' propagation
1、PROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启。
2、PROPAGATION_SUPPORTS:如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。
3、PROPAGATION_MANDATORY:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4、PROPAGATION_REQUIRES_NEW:总是开启一个新的事务。如果一个事务存在,则将这个存在的事务挂起。
5、PROPAGATION_NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务。
6、PROPAGATION_NEVER:总是非事务地执行,如果存在一个活动事务,则抛出异常。
7、PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按TransactionDefinition.PROPAGATION_REQUIRED属性执行

2' isolation
1、ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。
2、ISOLATION_READ_UNCOMMITTED:这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。
3、ISOLATION_READ_COMMITTED:保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
4、ISOLATION_REPEATALBE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻想读。它除了保证一个事务不能读取另外一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5、ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不课重复读外,还避免了幻想读。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值