spring事务管理
author:z_xiaofei168
6.1、spring的事务管理器
Spring框架并没有直接管理用户的应用系统中的事务,它只是提供许多供用户选择的事务管理器,然后将事务管理的责任委托给与此事务管理器对应的持久化技术的事务实现。
事务管理实现
使用时机
org.springframework.jdbc.datasource.
DataSourceTransactionManager
在单一的JDBC DataSource中管理事务
org.springframework.orm.hibernate3.
HibernateTransactionManager
当持久化机制是Hibernate时,用它来管理职务
org.springframework.orm.
jpa.JpaTransactionManager
当JPA用作持久化时,用它来管理职务
org.springframework.transaction.
jta.JtaTransactionManager
使用一个JTA实现来管理事务。在一个事务跨越多个资源时必须使用
配置文件中的配置如下:
<bean id=”transactionManager” class=” org.springframework.jdbc.datasource. DataSourceTransactionManager”>
<property name=”dataSource” ref=” dataSource”/>
</bean>
6.2、事务属性介绍
1>.传播行为
传播行为
说明
PROPAGATION_REQUIRED
必须在一个事务中执行。如果当前有一个事务正在进行,该方法将会在那个事务中执行。否则要开始一个新事务。Spring事务传播行为的默认值。
PROPAGATION_SUPPORTS
支持现有的事务。如果当前没有事务在进行,就以非事务的方式执行
PROPAGATION_MANDATORY
方法必须在一个现有事务中进行,否则会抛出异常。
PROPAGATION_REQUIRES_NEW
必须在它自己的新启事务里进行。如果现有事务在进行就先暂停它
PROPAGATION_NOT_SUPPORTED
不应在事务中进行。如果现有事务在进行就先暂停它
PROPAGATION_NEVER
不应在事务中进行。如果现有事务在进行就抛出异常
PROPAGATION_NESTED
如果现有事务正在进行,则该方法运行在一个嵌套式事务中。否则PROPAGATION_REQUIRED执行
2>.隔离级别
隔离级别
说明
ISOLATION_DEFAULT
使用底层数据库默认的隔离级别spring事务隔离级别的默认值
ISOLATION_READ_UNCOMMITED
充许另一个事务可以读到这个事务未提交的数据可能导致脏读、不可重复读和幻读。
ISOLATION_READ_COMMITED
保证一个事务修改的数据提交后才能被另一个事务读取可能导致不可重复读和幻读。
ISOLATION_REPEATABLE_READ
要求对相同字段的多次读取的结果必须相同,除非事务本身更新了数据可能导致幻读。
ISOLATION_SERIALIZABLE
事务被处理为顺序执行可以防止脏读、不可重复读、幻读。
3>.只读提示
如果事务只对后端数据进行读操作,则后端数据库可以采用一些优化措施来提高执行效率。但必须在事务中才有效。也就是说要搭配传播行为PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED 来设置。
4>.事务超时间隔
还可以设置事务的超时间隔,让事务在特定秒数后自动回滚,不必等它自己结束。由于计时是从事事务开始时算起的,所以它也得搭配传播行为为 PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED 来设置。
5>.回滚规则
当事务运行过程中抛出异常时,事务可以被声明为回滚或者不回滚。默认情况下只在出现RuntimeExceptio才会回滚,而在出现受检异常时不回滚。
当然,也可以改变这种回滚规则,可以声明一个事务在出现特定的受检异常时能回滚。也可以声明一个事务在出现特定的非受检异常时不回滚。
6.3、声明式事务管理
1>.基于xml配置方式
第1步:定义事务通知
第2部:把事务通知绑定到切入点
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-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- 配置不带连接池的数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///spring" />
<property name="username" value="root" />
<property name="password" value="123" />
</bean>
<!-- JDBC事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- DataSource事务管理器需要数据源实例 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 第1步:定义事务通知(主要是针对指定事务管理器对应的事务实现配置事务参数) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 对选定的方法配置详细的事务属性 -->
<tx:method name="find*" read-only="true" />
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 第2步:AOP配置 -->
<aop:config>
<!-- 声明事务切入点(配置哪些类的哪些方法参与事务) -->
<aop:pointcut id="AllServiceMethod"
expression="execution(* com.zxf.service.*.*(..))" />
<!-- 通知器(把事务通知绑定到切入点) -->
<aop:advisor pointcut-ref="AllServiceMethod" advice-ref="txAdvice" />
</aop:config>
<!-- 以下是Spring容器管理的Bean -->
<bean id="accountDao" class="com.zxf.dao.AccountDaoJDBCImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="accountService" class="com.zxf.service.AccountService">
<property name="accountDao" ref="accountDao"/>
</bean>
<!-- Hibernate事务管理器
<bean id="txManager2"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref ="sessionFactory"/>
</bean>
-->
<!-- JPA事务管理器
<bean id="txManager3"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref ="entityManagerFactory"/>
</bean>
-->
</beans>
2>.基于注解方式
第1步:在spring配置文件中启用对AspectJ注解的支持
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-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- 配置不带连接池的数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///spring_04" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- JDBC事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- DataSource事务管理器需要数据源实例 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 启用对事务注解的支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 以下是Spring容器管理的Bean -->
<bean id="accountDao" class="com.zxf.dao.AccountDaoJDBCImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="accountServiceByTxAnnotation"
class="com.zxf.service.AccountServiceByTxAnnotation">
<property name="accountDao" ref="accountDao"/>
</bean>
</beans>
第2步:用@Transactional注解指定接口、类或方法的事务属性
Java代码
package com.zxf.service;
import java.util.List;
import org.springframework.transaction.annotation.Transactional;
import com.zxf.dao.AccountDao;
import com.zxf.domain.Account;
/** Account业务逻辑类--基于注解方式的声明式事务管理配置 */
@Transactional //指定需要声明式事务,事务属性使用默认值
public class AccountServiceByTxAnnotation {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao){
this.accountDao = accountDao;
}
}