Spring事务
一、概述
1、传播机制(Propagation)
A业务方法调用B业务方法,如果A……,则B……
-
REQUIRED:默认的传播特性,如果当前没有事务,则新建一个事务,如果当前存在事务,则加入这个事务。(无则新建,有则加入)
-
SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,则以非事务的方式执行(有则加入,无则无为)
-
MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常(有则加入,无则警告)
-
REQUIRED_ NEW:创建一个新事务,如果存在当前事务,则挂起该事务(无则新建,有则挂起)
-
NESTED:如果当前事务存在,则在嵌套事务中执行,否则和REQUIRED的操作一样(新建一个事务)。(无则新建,有则嵌套;需要注意的是,NESTED仅支持JDBC,不支持JPA或者Hibernate)
-
NOT_ SUPPORTED:以非事务方式执行,如果存在当前事务,则挂起当前事务*(有则挂起,无则无为)
-
NEVER:不使用事务,如果当前事务存在,则抛出异常*(有则警告,无则无为)
-
NESTED和REQUIRED_ NEW的区别:
REQUIRED_ NEW是新建一个事务并且新开始的这个事务与原有事务无关, 而NESTED则是当前存在事务时会
开启一个嵌套事务,在NESTED情况下,父事务回滚时,子事务也会回滚,而REQUIRED_ NEW情况下,原有事务
回滚,不会影响新开启的事务 -
NESTED和REQUIRED的区别:
REQUIRED情况下,调用方存在事务时,则被调用方和调用方使用同一个事务,那么被调用方出现异常时,由
于共用一个事务,所以无论是否catch异常,事务都会回滚,而在NESTED情况下,被调用方发生异常时,调用方
可以catch其异常,这样只有子事务回滚,父事务不会回滚。
-
-
超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
-
是否只读:查询时设为只读。
2、隔离级别(Isolation)
- READ_UNCOMMITTED
- READ_COMMITTED
- REPEATABLE_READ
- SERIZALZABLE
- DEFAULT
在进行配置的时候,如果数据库和Spring代码中的隔离级别不同,那么以Spring的配置为主。
3、实现原理
在使用Spring框架的时候,可以有两种事务的实现方式:
- 编程式事务:由用户自己通过代码来控制事务的处理逻辑,
- 声明式事务: 通过
@Transactional
注解来实现。
其实事务的操作本应由数据库来进行控制,但是为了方便用户进行业务逻辑的操作, Spring对事务功能进行了扩展实现,一般很少会用编程式事务,更多的是通过添加@Transactional
注解来进行实现。
当添加@Transactional
注解之后数据库事务的自动功能就会关闭,由Spring框架来帮助进行控制。
其实事务操作是AOP的一个核心体现,当一个方法添加@Transactional注解之后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当使用这个代理对象的方法的时候,如果有事务处理,那么会先把事务的自动提交给关系,然后去执行具体的业务逻辑,如果执行逻辑没有出现异常,那么代理逻辑就会直接提交,如果出现任何异常情况,那么直接进行回滚操作,当然用户可以控制对哪些异常进行回滚操作。
4、Spring事务什么时候会失效?
- 1、bean对象没有被Spring容器管理
- 2、方法的访问修饰符不是public
- 3、自身调用问题
- 4、数据源没有配置事务管理器
- 5、数据库不支持事务
- 6、异常被捕获
- 7、异常类型错误或者配置错误
二、编程式事务
相关对象
※1、PlatformTransactionManager
Spring的事务管理器,其中提供了常用的操作事务的方法。需要设置事务管理器。
方法 | 说明 |
---|---|
TransactionStatus getTransaction (TransactionDefination defination) | 获取事务的状态信息 |
void commit (TransactionStatus status) | 提交事务 |
void rollback (TransactionStatus status) | 回滚事务 |
- 注意:PlatformTransactionManager是接口类型,不同的Dao层技术则有不同的实现类,例如:
- Dao层技术是JDBC或Mybatis 时: org. springframework. jdbc . datasource . DataSourceTransactonManager
- Dao层技术是Hibernate时: org . springframework . orm. hibernate5. HibernateTransactionManager
※2、TransactionDefinition
事务的定义信息对象,其中有如下方法:
方法 | 说明 |
---|---|
int getISolationLevel () | 获得事务的隔离级别 |
int getPropogationBehavior () | 获得事务的传播行为 |
int getTimeout () | 获得超时时间 |
boolean isReadonly() | 是否只读 |
需要设置事务的隔离级别、传播行为、超时时间、是否只读。
※3、TransactionStatus
接口提供的是事务具体的运行状态,方法介绍如下。
方法 | 说明 |
---|---|
boolean hasSavepoint () | 是否存储回滚点 |
boolean isCompleted () | 事务是否完成 |
boolean i sNewTransaction () | 是否是新事务 |
boolean isRollbac konly () | 事务是否回滚 |
三、声明式事务
Spring的声明式事务顾名思义就是采用声明的方式来处理事务。
声明是指在配置文件中声明,用在Spring配置文件中声明式的处理事务来代替代码式的处理事务。
- 声明式事务处理的作用
- 事务管理不侵入开发的组件。 具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可
- 在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便
- 注意: Spring 声明式事务控制底层就是AOP。
(1)XML形式
1、导入相关依赖
2、导入tx的xsd约束
3、配置
<context:property-placeholder location="classpath:jdbcConfig.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <!--配置事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--配置事务通知--> <!--事务管理器ID为transactionManager时,可省略--> <tx:advice id="txAdvice"> <tx:attributes> <!--事务属性的配置--> <tx:method name="transfer*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" timeout="10"/> <tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" timeout="5"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!--配置织入关系--> <aop:config> <!--由于Spring已经对事务通知封装完成,使用aop:advisor即可--> <!--对业务层下的所有类的所有任意参数类型及任意返回值类型的方法(切点)进行增强--> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.ming.service.impl.*.*(..))"/> </aop:config> <context:component-scan base-package="com.ming"/>
(2)注解形式
-
1、导入相关依赖
-
2、导入tx的xsd约束
-
3、在需要事务控制的方法上添加
@Transactional
注解(也可以在类上添加,表示该类中的所有方法遵循该注解的配置进行事务)@Transactional( isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = {RuntimeException.class,Error.class} ) public class AccountServiceImpl implements AccountService { }
-
4、开启事务的注解驱动
<tx:annotation-driven transaction-manager="transactionManager"/> <!--事务管理器ID为transactionManager时,可省略-->