Spring提供了编程性事务管理与声明式的事务管理。Spring事务管理的抽象关键在于org.springframework.transaction.PlatformTransactionManager接口的实现。
PlatfromTransactionManager接口有许多具体的事务实现类,例如:DataSourceTransactionManager、HibernateTransactionManager、JdoTransactionManager,JtaTransactionManager等等。
此处需要注意的是,要使用Mysql数据库进行事务处理,必须建立支持事务的表类型,例如:InnoDB的表类型。
1、 Spring提供的编程性事务
可以清楚的控制事务的边界,自行实现事务的开始时间,撤销时间,结束时间等,可以实现细粒度的事务控制。
编码例子如下:
private PlatformTransactionManager txManager;
public voidsetTxManager(PlatformTransactionManager txManager) {
this.txManager = txManager;
}
public void {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try{
JdbcTemplate tmp = new JdbcTemplate(dataSource);
tmp.execute("insert into tbl_user (name,pwd) values ('"+user.getName()+"','"+user.getPwd()+"')");
//写错的sql,等着抛出运行时异常
tmp.update("sssssssssssss");
UserUpdate uu = new UserUpdate(dataSource);
uu.update(new Object[]{user.getName(),user.getPwd()});
}catch(DataAccessException e){
txManager.rollback(status);
throw e;
}
txManager.commit(status);
}
配置文件的写法如下:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="userDao" class="com.itcast.dao.impl.UserDaoImpl">
<property name="dataSource" ref="dataSource"></property>
<property name="txManager" ref="txManager"></property>
</bean>
2、 声明式的事务管理
Spring事务的相关API可以不用介入程序之中,只是在配置文件上修改配置下就可以移去事务管理服务。Spring的声明式事务是通过spring的AOP来实现的,所以执行程序的时候,请记得将spring-aop.jar给放到classpath中。
1)、最基础的事务配置如下:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="userDao" class="com.itcast.dao.impl.UserDaoImpl">
<property name="dataSource" ref="dataSource"></property>
<property name="txManager" ref="txManager"></property>
</bean>
<!-- 事务代理 -->
<bean id="userDaoTxProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="userDao"></property>
<property name="transactionManager" ref="txManager"></property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
</props>
我们在使用的时候只是需要取得userDaoTxProxy 而不是userDao就可以完成对这个Dao的事务控制了。
2)、将事务抽象提取,让我们的代理类取得一个拦截器方式的事务,从而将每个代理类的事务都抽象出来集中管理,这样只要我们命名规范,那么我们的事务处理就更加容易。
例如:
<!-- 将事务控制集中到一个bean中 -->
<bean id="transactionInteceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="txManager"></property>
<property name="transactionAttributeSource" >
<value>com.itcast.dao.impl.UserDaoImpl.insert*=PROPAGATION_REQUIRED</value>
</property>
</bean>
<bean id="userDaoTxProxy1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userDao"></property>
<property name="interceptorNames">
<list>
<value>transactionInteceptor</value>
</list>
</property>
</bean>
注意这个bean的class实例式我们平时使用的代理dao的ProxyFactoryBean,而不是上边的TransactionProxyFactoryBean实例,这样也就要求我们只能使用拦截器的方式将我们的事务切入到程序中。我们在调用userDao的时候,通过获取userDaoTxProxy1 就可以得到一个经过事务控制的bean了。
3、 事务属性的介绍
1)、传播行为:(7种)
PROPAGATION_REQUIRED:支持现在的事务,如果没有就创建一个
PROPAGATION_MANDATORY:必须在一个现存的事务中,否则就抛异常
PROPAGATION_NEST:在一个嵌入的事务中进行,如果不是,则同PROPAGATION_REQUIRED
PROPAGATION_NEVER:不应当在事务中进行,如果有就抛出异常
PROPAGATION_NOT_SUPPORTED:不应当在事务中进行,如果有就暂停当前的事务
PROPAGATION_REQUIRES_NEW:建立一个新的事务,如果现存一个事务就暂停它
PROPAGATION_SUPPORTS:支持现在的事务,如果没有,就以非事务的方式执行。
2)、隔离层级
可以让你根据实际的需求来对数据进行锁定设置。Spring提供的隔离层级的设置可以在TransactionDefinition的API文档说明上有。
3)、只读提示
如果事务只进行读取的动作,则可以利用底层数据库在只读操作时发生的一些最佳化动作,由于这个动作利用到数据库的只读的事务操作最佳化,因此必须在事务中才有效。
4)、事务超期时间
有的事务操作可能延续很长一段时间,事务本身可能关联到数据表格的锁定,因此长时间的事务操作会有效率上的问题。对于过长的事务操作,您要考虑Roll Back事务并要求重新操作,而不是无限时的等待事务完成。
4、 TransactionAttributeSource、TransactionAttribute
在TransactionProxyFactoryBean上有setTransactionAttributeSource()与setTransactionAttribute的方法,他们是用来设置事务属性的策略实例
5、 Spring2.0的声明式事务管理:基于XML Schema
在spring2.0中要设置声明式事务管理,可以依赖于spring2.0的<aop>与<tx>标签,因而要记得加入相关的名称空间声明:
1)、给Bean标签增加相关的声明
<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-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
">
2)、写配置文件
<!-- 使用spring2.0的标签来声明事务 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="userDaoPointcut"
expression="execution(* com.itcast.dao.IUserDao.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="userDaoPointcut"/>
</aop:config>
注意到<tx:method>中的属性设置,对于传播行为、隔离层级、只读、超时、异常时撤回或者提交,都有对应的“propagation”、“isolation”、“timeout”、“read-only”、“rollback-for”、“no-rollback-for”属性可以设置.若不设置,“propagation”的属性默认值为“REQUIRE”,“isolation”的默认值为“DEFAULT”,“timeout”的默认值为“-1(单位是秒)”、“read-only”
的默认值是“false”
与先前介绍的spring2.0基于XML Schemal的AOP设置相同,由于不再于设置文件中设置代理对象,所以直接取得“userDao”的实例进行操作就ok了。