Spring-Spring事务管理


Spring-Spring事务管理

 


         Spring是一般系统架构中的管理者,负责管理其它框架,协调各个部分的工作。Spring的事务管理有两种编程式事务和声明式事务,在了解如何使用Spring事务之前我们先了解一下与事务/Spring事务有关的一些概念。

 

         什么是事务

 

         概要

         事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。在事务的一个执行单元中的一系列操作,要么完全执行,要么完全不执行。

 

         特性

         原子性

         事务是一个不可分割的工作单位,事务中的操作要么完全执行,要么完全不执行

         一致性

         事务前后数据的完整性必须保持一致,组成一个事务的各种操作,要么全部执行成功,要么全部执行失败。

         隔离性

         指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间需要相互隔离

         持久性

         指一个事务一旦被提交,它对数据库中的数据的改变就是永久性的,即使数据库发生故障也不应该对其有任何影响


         Spring事务管理

         Spring管理高层抽象主要包括3个接口,分别是

         ·PlatformTransactionManager事务管理器

         ·TransactionDefinition(事务定义信息(隔离、传播、超时、只读)

         ·TransactionStatus事务具体运行装填

         下面就各自简单的介绍一下这几个接口。


         PlatfromTransactionManager

         Spring为不同的持久化框架提供了不同的PlatformTransactionManager接口实现,如下图

事务 说明
org.springframework.jdbc.datasource.DataSourceTransactionManager 使用Spring JDBC或ibatis/Mybatis进行持久化时使用
org.springframework.orm.hibernate3(4).HibernateTransacionManager 使用Hibernate3.0(4.0)版本进行持久化数据时使用
org.springframework.orm.jpa.JpaTransactionManager 使用JPA进行持久化时使用
org.springframework.orm.jdo.JdoTransactionManager 当持久化机制是Jdo时使用
······ ······

         TransactionDefinition

         如果在事务中我们不考虑隔离性,可能会应发:脏读、不可重复读、幻读

         脏读

         一个事务中读取了另外一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。

         不可重复读

         在同一事务中,多次读取同一个数据返回的结果有所不同。

         幻读

         一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了,再后来的查询中,第一个事务就会发现有些原来没有得记录。

         事务的几种隔离级别

隔离级别 含义
DEFAULT 使用后端数据库默认的隔离级别(spring中的选择项)
READ_UNCOMMITED 允许读取还未提交的改变了的数据,可能导致脏读、幻读、不可重复读
READ_COMMITED 允许在并发事务已经提交后读取,可防止脏读,但幻读和不可重复读仍可发生
REPEATABLE_READ 对相同字段的国瓷读取是一直的,除非数据被事务本身改变。可防止脏读和不可重复读,但幻读仍可能发生
SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。
          备注:最后一种级别,通过完全锁定在事务中涉及的数据表来完成,安全性最好,性能最低。如果使用的是Mysql数据库默认的是REPEATABLE_READ,如果使用的是Oracle则默认READ_COMMITED。


         事务的传播行为

         当有复杂的方法需要service中的另外两个方法才能完成是,这个时候我们就要考虑使用事务的传播行为解决service中方法相互调用的问题。

         

事务传播行为类型 说明
PROPAGATION_REQUIRED 支持当前事务,如果不存在就新建一个事务
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,就抛出异常
PROPAGATION_REQUIRES_NEW 如果有当前事务存在,挂起当前事务,创建一个新的事物
PROPAGATION_NOT_SUPPORTED 以非事务的方式运行,如果有当前事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务的方式运行,如果当前事务存在,就抛出异常
PROPAGATION_NESTED 若果当前事务存在,则嵌套事务执行

         上面介绍的7种传播行为,大概可以分为3类。1-3分为一类,保证了两个方法在同一个事务中执行;4-6是一类,保证不再一个事务中执行;最后一个是一类,一个事务中嵌套另外一个事务(第一个方法执行完之后设置保存点,第二个方法发生异常回滚到保存点或者最初始状态)。

         事务的传播行为主要解决业务层方法间的相互调用所产生的事务应该如何进行传递的问题。


         超时

         设置事务的超时时间


         只读

         该事务只允许读,不允许增、删、改。


         TransactionStatus

         其实是SavepointManager接口的实现,接口,执行一个API以编程的方式管理事务以通用的方式保存事务节点状态。


         Spring管理事务的两种方式


         编程式事务


         该方式在实际开发过程中基本不用,通过TransactionTemplate手动管理事务,与业务层代码耦合,增加了开发人员的工作量,同时不利于后期的维护拓展。

         编程式事务分为这么几步:配置事务管理器、配置模板、业务层注入、业务层代码编写。

         配置文件

<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
	<property name="transactionManager" ref="transactionManager"/>
</bean>
<!-- 业务注入 -->
<bean id="testService" class="com.cody.service.TestService">
	<property name="testDao" ref="testDao"/>
	<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>

         代码中需要注入

public class TestServiceImpl implements TestService {
	
	//注入事务管理模板
	private TransactionTemplate transactionTemplate;
	
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}

	@Override
	public void Transferable(){
			
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				//具体的业务实现
				······
			}
		})
	}

}

         声明式事务


         声明式事务一共有三种,下面我们一一道来。


        使用XML声明式

<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置业务层代理 -->
<bean id="testServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
	<!-- 配置目标对象 -->
	<proterty name="target" ref="testService"/>
	<!-- 注入事务管理器 -->
	<proterty name="transactionManager" ref="transactionManager"/>
	<!-- 注入事务属性 -->
	<property name="transactionAttributes">
		<props>
			<!-- 
			*PROPAGATION  :事务的传播行为
			*ISOLATION    :事务的隔离级别
			*readOnle     :只读
			*-Exception   :发生哪些异常回滚
			*+Exception   :发生哪些异常不回滚
			 -->
			<prop key="transfer">PROPAGATION_REQUIRED</prop>	
		</props>
	</property>
</bean>

         代码中需要注入通过@Resource(name="testServiceProxy")即可


         基于tx/aop的XML方式

<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务通知:(事务增强) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<!-- 传播行为 -->
		<tx:method name="transfer" propagation="REQUIRED"/>
	</tx:attributes>
</tx:advice>
<!-- aop配置切面 -->
<aop:config>
	<!-- 配置切入点 -->
	<aop:pointcut expression="execution(* com.cody.service.impl.*.*(..))" id="pointcut"/>
	<!-- 配置切面 -->
	<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>

	<!-- 简写模式 -->
<!-- 	<aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.itcast.ssm.service.impl.*.*(..))"/> -->
</aop:config>

         注意:该方法需要在配置文件中引入aop和tx命名空间如下图

Spring-Spring事务管理_第1张图片

         

         基于注解的方法

这种方法配置文件如下,由于需要在业务层中添加注解不利于维护和以后的修改。

<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven/>

在方法中只须在类名上@Transaction(···)括号中配置具体的传播行为等即可


总结

在笔者的项目中使用的是AspectJ的XML方法,当然这也是最常用的方法,希望笔者的这篇文章对正在了解这方面知识的朋友们提供到帮助。


       

你可能感兴趣的:(Spring-Spring事务管理)