想起小时候,玩翘翘板,如果同伴不玩的话,那两个人就都玩不了,只能一起玩,或者都不玩,在软件中,发生或都不发生(all-or-noting)就称做事务了。事务保证在一个单元内的所有操作要么都发生要么都不发生。
用四个词来概括事务就是:原子性(Atomic)一致性(Consistent),隔离性(Isolated),持久性(Durable),简称ACID.
Spring 和ejb一样,支持两种事务,编程式事务和声明式事务。编程式事务允许你通过代码去控制你的事务,声明式事务允许你通过容器来定义事务的条件,隔离级别,和超时等。不管你选择哪种事务,你都将用到spring 的事务管理接口,不同的平台,spring都有不同的实现,下表是spring针对不同的数据操作提供的事务管理:
Transaction manager (org.springframework.*) |
Use it when... |
|
jca.cci.connection. |
Using Spring’s support for Java EE Connector Architec- |
|
CciLocalTransactionManager |
Working with Spring’s 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.jta.OC4JJtaTransactionManager |
Using Oracle’s OC4J JEE container. |
|
transaction.jta.WebLogicJtaTransactionManager |
You need distributed transactions and your application is |
|
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异常继续提交。
Propagation有7种可选的值,分别是:
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 transaction’s 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 |
|
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