spring transactions

想起小时候,玩翘翘板,如果同伴不玩的话,那两个人就都玩不了,只能一起玩,或者都不玩,在软件中,发生或都不发生(all-or-noting)就称做事务了。事务保证在一个单元内的所有操作要么都发生要么都不发生。

用四个词来概括事务就是:原子性(Atomic)一致性(Consistent,隔离性(Isolated,持久性(Durable,简称ACID.

Spring ejb一样,支持两种事务,编程式事务和声明式事务。编程式事务允许你通过代码去控制你的事务,声明式事务允许你通过容器来定义事务的条件,隔离级别,和超时等。不管你选择哪种事务,你都将用到spring 的事务管理接口,不同的平台,spring都有不同的实现,下表是spring针对不同的数据操作提供的事务管理:

Transaction manager (org.springframework.*)

Use it when...

 

jca.cci.connection.

Using Springs support for Java EE Connector Architec-
ture (JCA) and the Common Client Interface (CCI).

 
 

CciLocalTransactionManager

Working with Springs JDBC abstraction support. Also

 

jdbc.datasource.DataSourceTransactionManager

useful when using iBATIS for persistence.

 

jms.connection.JmsTransactionManager

Using JMS 1.1+.

 

jms.connection.JmsTransactionManager102

Using JMS 1.0.2.

 

orm.hibernate3.HibernateTransactionManager

Using Hibernate 3 for persistence.

 

orm.jdo.JdoTransactionManager

Using JDO for persistence.

 

orm.jpa.JpaTransactionManager

Using the Java Persistence API (JPA) for persistence.

 

transaction.jta.JtaTransactionManager

You need distributed transactions or when no other
transaction manager fits the need.

 
 

transaction.jta.OC4JJtaTransactionManager

Using Oracles OC4J JEE container.

 

transaction.jta.WebLogicJtaTransactionManager

You need distributed transactions and your application is
running within WebLogic.

 

transaction.jta.WebSphereUowTransactionManager

You need transactions managed by a UOWManager in WebSphere.

 

 

 

JDBC事务:

<bean id="transactionManager" class="org.springframework.jdbc.

datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>

</bean>

Hiberante事务:

<bean id="transactionManager" class="org.springframework.

      orm.hibernate3.HibernateTransactionManager">

<property name="sessionFactory" ref="sessionFactory"/>

</bean>

Jpa事务:

<bean id="transactionManager"

   class="org.springframework.orm.jpa.JpaTransactionManager">

<property name="entityManagerFactory" ref="entityManagerFactory" />

</bean>

下边这个是不知道用哪个事务的时候用,或者有多个事务源的时候用

<bean id="transactionManager" class="org.springframework.

transaction.jta.JtaTransactionManager">

<property name="transactionManagerName"

value="java:/TransactionManager" />

</bean>

下边介绍下编程式事务和声明式事务:

编程式事务:直接看代码例子吧

public void saveSpittle(final Spittle spittle) {

         txTemplate.execute(new TransactionCallback<Void>() {

                   public Void doInTransaction(TransactionStatus txStatus) {

                            try {

                                              spitterDao.saveSpittle(spittle);

                                               } catch (RuntimeException e) {

                                               txStatus.setRollbackOnly();

                                               throw e;

                            }

                   return null;

                   }

                   });

}

注入txTemplate

<bean id="spitterService"

   class="com.habuma.spitter.service.SpitterServiceImpl">

...

<property name="transactionTemplate ">

<bean class="org.springframework.transaction.support.

TransactionTemplate">

<property name="transactionManager"

ref="transactionManager" />

</bean>

</property>

</bean>

声明式事务:首先讲下声明式事务的五个属性吧

事务的传播级别(Propagation,事务的隔离性(Isolation,(不)回滚条件(Rollback rules,超时时间(Timeout,是否只读(Read-only),

1.spring中事务配置属性以及@Transaction对应的默认值。一般使用默认值即可,特殊情况自定义。
1)事务传播行为(propagation):默认PROPAGATION_REQUIRED
2)事务隔离级别(isolation):默认ISOLATION_DEFAULT(数据库默认的隔离级别)
3)只读还是读写(readonly):默认读写事务。
4)异常发生时回滚还是提交(rollback-for/no-rollback-for):默认checked异常引发回滚,unchecked异常继续提交。

 

Propagation7种可选的值,分别是:

PROPAGATION_MANDATORY,需要在有事务的情况下运行,否则throw exception

PROPAGATION_NESTED ,内联事务,就是如果一个事务已经在运行了,会重新开启内置一个事务,可以提交,回滚,如果没有事务在运行,情况就和PROPAGATION_REQUIRED一样,

PROPAGATION_NEVER不多说,和PROPAGATION_MANDATORY完全相反

PROPAGATION_NOT_SUPPORTED:不需要在事务在运行,如果当前有事务,那么当前程序会挂起。

PROPAGATION_REQUIRED需要在事务的环境下运行,没有的话会新建一个事务。

PROPAGATION_ REQUIRES_NEW:new一个新的事务,在自己的事务里运行

PROPAGATION_SUPPORTS:以有事务环境下运行,如果有事务的话。

 

Isolation,隔离级别是用来防止脏读,不可重复读,幽灵数据,隔离级别有下边5个可选属性:

ISOLATION_DEFAULT, ISOLATION_READ_UNCOMMITTED(允许读没有提交的数据,上边三种读都是防止不了的)ISOLATION_READ_COMMITTED(允许读提交了的数据,能防止脏读),

ISOLATION_REPEATABLE_READ(能防止脏读和不可重复读), ISOLATION_SERIALIZABLE(都能防止了,ACID级别的了,全加锁,不过也是最慢的了)

Read-only,只读事务,这个需要配置的程序在事务环境下运行

Transaction Timeout 事务超时

Rollback rules 回滚条件

下边讲下这五个属性在xml文件中是如何配置的:首先加入声明吧

<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/aop

http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"

注意,这里边要加入aop的声明,因为事务的切入点用到了

配置形式:

<tx:advice id="txAdvice">

         <tx:attributes>

                   <tx:method name="add*" propagation="REQUIRED" />

                   <tx:method name="*" propagation="SUPPORTS"

                   read-only="true"/>

         </tx:attributes>

</tx:advice>

<tx:method>用上边讲述的5个属性来定义事务

Attribute

Purpose

 

isolation

Specifies the transaction isolation level.

 

propagation

Defines the transactions propagation rule.

 

read-only

Specifies that a transaction be read-only.

 

Rollback rules:

rollback-for specifies checked exceptions for which a transaction

 

rollback-for

should be rolled back and not committed.

 

no-rollback-for

no-rollback-for specifies exceptions for which the transaction
should continue and not be rolled back.

 
 

timeout

Defines a timeout for a long-running transaction.

 

下边配置切入点:

<aop:config>

         <aop:advisor

         pointcut="execution(* *..SpitterService.*(..))"

         advice-ref="txAdvice"/>

</aop:config>

通过注解方式配置:

<tx:annotation-driven transaction-manager="txManager" />,这句话就告诉spring去检查上下文中所有的bean,和用@Transactional标注了的。看下边的例子:

 

@Transactional(propagation=Propagation.SUPPORTS, readOnly=true)

public class SpitterServiceImpl implements SpitterService {

...

         @Transactional(propagation=Propagation.REQUIRED, readOnly=false)

         public void addSpitter(Spitter spitter) {

         ...

         }

         ...

}

 

6.常见的错误:
是希望在service方法中catch到spring的异常,抛出一个自定义异常,但是不继承自DataAccessException的。可惜的是这样做是catch不到spring的异常的。

原因:
spring是靠捕获方法抛出的DataAccessException来处理事务的,若被我们自己catch到了,spring就不可能再捕获到异常,就没法处理事务了。

解决:
可以在service方法中catch到spring的异常,然后抛出一个自定义但必须继承自DataAccessException的异常。因为自定义的异常是继承自DataAccessException的,因此spring能够catch到并处理事务的。

 

7,在事务属性为REQUIRED时,在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中。如果互相嵌套调用的事务方法工作在不同线程中,则不同线程下的事务方法工作在独立的事务中。

 

 From spring in action 3

猜你喜欢

转载自hyp1987.iteye.com/blog/1484848