天天看点

Spring事务Spring事务管理2、事务的属性3 事务管理器4. Spring编程式管理事务5. Spring声明式管理事务

转载请注明出处:https://mp.csdn.net/mdeditor/83614701

Spring事务管理

Spring支持支持编程式和声明式两种事务管理。编程式事务管理是在业务中嵌入控制事务提交和回滚的事务管理代码来实现。通常在方法正常完成时提交事务,而在方法抛出异常是回滚事务。使用编程式事务,你可以定义自己的事务提交和回滚规则。

声明式的事务管理的灵活性不如编程式,编程式事务管理允许你通过代码控制事务-----显示的在在你觉得合适的时候启动、提交、合并事务。你可以指定一组事务的属性,在很细的粒度上定义事务。

2、事务的属性

  • 原子性 :事务是包含一系列操作的的原子操作,这些操作要么全部完成,要么全部不完成。
  • 一致性: 一旦事务的所有操作结束,事务就被提交。然后你的数据和资源将处于遵循业务规则的的一致性装态。
  • 隔离性:在相同数据数据集上同时可能有多个事务处理,每个事务应该与其它事务隔离,避免数据被破换。
  • 持久性: 一旦事务完成,它的结果应该能承受任何系统错误(想象一下事务在提交过程中被切断电源的情况)。通常,事务的结果被写入持续性存储。

2.1 jdbc管理事务

try {
	conn = datasource.getConnection;
	conn.setAutoCommit(false);
	...这里写操作数据库的业务代码...
	conn.commit();
	} catch (SQLException e ) {
		if (conn!=null) {
			try {
				conn.rollback();
			} catch (SQLException e) {}
		}
	} finally {
		if (conn!=null) {
			try {
			conn.close();
			} catch (SQLException e) {}
		}
	}
           

这种代码是JDBC专用的,一旦你选择其它数据访问策略,这些代码也需要改变。Spring事务支持提供了一组技术独立的机制,包括事务管理器、事务模板、和事务声明式支持以简化你的事务管理任务。

3 事务管理器

Spring帮我们从不同的事务管理API中抽象出了一组通用的事务机制,作为开发人员你只要利用Spring的事务机制,不需要知道太多底层的细节,你的事务管理代码将独立于任何特定的事务技术。

Spring的核心事务管理抽象基于PlatformTransactionManager接口,它封装了一组用于事务管理的技术独立代码。不论你在Spring选择哪一种事务管理策略(声明式或者编程式)都需要事务管理器,PlatformTransactionManager提供三种处理事务的方法:

  • TranscactionStatus getTransaction(TransactionDefination definition)throws TransactionException
  • void commit(TransactionStatus status)
  • void rollback(TransactionStatus status)

3.1 事务管理器的实现

PlatformTransactionManager只是一个接口,这个接口有多重实现。

  • 应用程序只有一个数据源并且使用JDBC进行访问,使用DataSourceManager。
  • 如果使用orm框架访问数据库,则选择对应该框架的事务管理器。例如HiberateTransactionManager。
Spring事务Spring事务管理2、事务的属性3 事务管理器4. Spring编程式管理事务5. Spring声明式管理事务

PlatformTransactionManager接口常见实现图

因此,我们在Spring的IOC容器中声明bean就行了。class是事务管理器的具体实现,还需要设置一个dataSource属性,以便管理这个数据源建立的连接。

4. Spring编程式管理事务

4.1 使用事务管理器编程式管理事务

前面说过无论是编程式事务管理 还是声明式事务管理都需要spring事务管理器。spring事务管理器提供了独立的api来管理事务。它提供了一套api

  • getTransaction() 启动新事务或者是获取当前活跃的事务。
  • commit()
  • rollback()

    使用事务管理器编程式管理事务的代码大致如下:

TransactionDefinition ref = new DefaultTransactionDefinition();
		TransactionStatus status = transactionManager.getTransaction(ref);
		try {
				//----这里写业务逻辑代码-----
				transactionManager.commit(status);
		} catch (Exception e) {
			 T.console(e.getMessage());
//			 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			 transactionManager.rollback(status);
			 return null;
		}
           

TransactionDefinition 对象用于指定事务属性,DefaultTransactionDefinition是它的一个实现,使用默认的属性。

4.2 使用事务模板编程式管理事务

如果你一直使用Spring事务管理器编程式管理事务,你看你会觉得厌烦,因为你一直在写重复的代码。因此,和JDBC模板一样,Spring提供了TransactionTemplate帮助你管理事务。你只需要在一个实现了TransactionCallback接口的回调类里封装你的业务代码,并将其传递给TransactionTemplate的execute方法执行就可以了

代码大致如下:

TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
		transactionTemplate.execute(new TransactionCallback<T>() {
			
			@Override
			public T doInTransaction(TransactionStatus status) {
//				这里写你的业务逻辑
				return null;
			}
		});
           

这种方法的好处在于不需要负责启动、回滚、或者提交事务。

在回调对象执行期间,如果抛出了一个非受控异常(例如:RuntimeException、DataAccessException),事务将会回滚,否则事务将在回调对象完成后提交。

建议不要向上面代码一样直接new 事务模板,最好交给Spring容器创建,事务模板依赖于事务管理器,相应的xml配置不做说明了。注意:事务模板实例是可以用于超过一个事务性的Bean的。因为它是一个线程安全对象,这也是为什么能放在容器中的原因了(spring创建的对象默认是单例的哦~)。

5. Spring声明式管理事务

因为事务管理是横切关注点,应该使用Spring声明式的管理事务。

5.1 使用事务通知声明式的管理事务

为了启用声明式的事务管理,你可以通过tx schema中定义的 tx:advice 声明一个事务通知,这样你必须要先添加schema约束。

如果你声明了这个通知,就必须将其与一个连接点相关联。因为事务通知在 <aop: config>元素之外声明,它不能与连接点直接链接,你必须在在<aop:config>元素中声明一个通知器(Advisor),将通知与切入点关联。

因为SpringAOP使用AspectJ切入点表达式定义切入点,因此必须添加AspectJ织入支持。

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.7.1</version>
        </dependency>
           

添加schame约束

<?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:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
	<!--  ....... -->
</beans>
           
<!-- 配置通知 -->
	<tx:advice id="xxxTransactionAdvice">
		<!-- 指定需要事务管理的方法 -->
		<tx:attributes>
		<!-- 匹配到类下方法的切入点 sava* 表示匹配所有以sava开头 的方法  -->
		<!-- 这里还可以配置事务定义 :传播行为  隔离级别  超时时间 是否只读  这里不配置全部使用默认的-->
			<tx:method name="save*"/>
		</tx:attributes>
	</tx:advice>	

		
	<aop:config>
		<!-- 表示在所有切入点加事务管理 -->
		<aop:pointcut expression="execution(* cn.pconline.activity.service.AwardService.*(..))" id="awardPointcut"/>
		<aop:advisor advice-ref="xxxTransactionAdvice" pointcut-ref="awardPointcut"/>
	</aop:config>
           

Spring AOP基于代理,它只能应用到公开方法,因此只有公共方法才能用Spring AOP声明为事务性的。

每个事务通知都需要声明一个事务管理器,如果你没有声明,Spring会在上下文中寻找一个bean名称为transactionManager的组件。

一切准备妥当 ,现在你可以从容器中获取AwardService的实例对象,这个bean的方法匹配该切入点,Spring将返回一个代理,为这个bean启动事务管理。

5.2 使用@Transactional注解声明式的管理事务。

在bean配置文件中声明事务用到AOP的相关知识,对于初学者来说,比较费劲。

因此,Spring允许通过@Transactional注解你的事务性方法,并且启用<tx:annotation-driven>元素声明注解。

由于SpringAOP基于代理的局限性,你应该只注解public 方法。

@Transactional注解可以用在类上,添加到类上时候,表示该类中所有的public方法将定义为事务性的

使用说明:

  • 在bean配置文件中声明中 ,开启注解支持的事务tx:annotation-driven 并为它注册一个事务管理器。
<?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"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
   <!-- 开启注解支持事务的功能 --> 
    <!-- 如果你未声明该属性,spring将在ioc容器中自动查找名为transactionManager的组件 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- 事务管理器 -->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/>
</beans>
           

Spring事务的使用方式就先介绍到这里,下一篇再详细介绍Spring事务的属性。