一、Spring事务的概述
- Spring事务机制主要包括
声明式事务
和编程式事务
。 - 一个业务逻辑方法往往包括一系列数据库原子访问操作,并且这些数据库原子访问操作应该绑定成一个整体,即要么全部执行,要么全部不执行,通过这种方式我们可以保证数据库的完整性,这就是事务。
- 事务是一个不可分割操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。
1.Spring事务的好处
- 事务可以使我们不需要去处理如何获取连接,关闭连接,事务提交和回滚等操作,也不再需要在事务相关的方法中处理大量的 try----catch-----finally 代码。
- 事务属性通常由
事务的传播行为
,事务的隔离级别
,事务的超时值
和事务只读标志
组成。
2.事务有四个特性
原子性(Atomicity)
:事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。一致性(Consistency)
:一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。隔离性(Isolation
):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。持久性(Durability)
:一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
二、Spring事务管理接口
1.Spring事务管理的API
Spring 框架中,最重要的事务管理的 API 有三个(后面详细说每一个)
TransactionDefinition
PlatformTransactionManager
TransactionStatus
2.事务管理器
- Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。
- Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
3.事务的传播行为
- 事务规则也就是事务传播行为,用于解决业务层方法之间的相互调用的问题
- 事务管理的主要任务是事务的创建,事务的回滚和事务的提交,是否需要创建事务及如何创建事务,是由事务传播行为控制的,通常数据的读取可以不需要事务管理,或者可以指定为只读事务,而对于数据的增加,删除和修改操作,则有必要进行事务管理。如果没有指定事务的传播行为,Spring默认采用REQUIRED。
4.常见的几类事务传播行为
REQUIRED
:表示当前方法必须运行在一个事务环境中,如果一个现有的事务正在运行,该方法将运行在这个事务中,否则就开始创建一个新的事务。REQUIRESNEW
:表示当前方法必须运行在自己的事务里SUPPORT
表示当前方法不需要事务处理环境,但如果有一个事务正在运行的话,则这个方法也可以运行在这个事务中。MANDATORY
:表示当前方法必须运行在一个事务上下文中,否则会抛出异常。NEVER
:表示当前方法不应该运行在一个事务上下文中,否则会抛出异常。
五、Spring声明式事务管理
- Spring声明式事务管理是建立在SpringAOP机制之上的,其本质式对目标方法前后进行拦截,在目标方法开始之前创建或者加入一个事务,在执行目标方法之后根据执行情况进行提交或者回滚事务。
- 声明式事务最大的有点在于不需要通过编程的方式管理事务,不需要在业务逻辑代码中掺杂事务管理的代码,只需要在配置文件中作出相关的事务规则声明,便可以将事务规则应用到业务逻辑中。
- 声明式事务得益于Spring IOC容器和Spring AOP机制的支持,IoC容器为声明式事务管理提供基础设施,是的Bean对于Spring框架而言是可管理的,由于事务管理本身就是一个典型的横切逻辑(AOP类似),因此Spring AOP机制是声明式事务管理的直接实现者。
- 声明式事务管理远优于编程式事务管理,这是Spring倡导的非侵入的开发方式,声明式事务管理使得业务代码不受干扰,一个普通的POJO对象,只要在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:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 引入外部属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置c3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置业务层 -->
<bean id="accountService" class="com.zzh.demo2.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!-- 配置DAO层,注入连接池就可以得到jdbc模板-->
<bean id="accountDao" class="com.zzh.demo2.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>