Spring中的事务控制
Spring中的事务控制
Spring中提供了分层设计的业务层事务处理解决方案
Spring中的事务控制也是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现
所谓事务控制,就是根据我们给定的事务规则来执行提交或回滚操作。
在这里再说一次事务的四个特性:ACID
- 原子性:(Atomicity)事务是一个不可分割的整体,要么全部完成,要么全部失败
- 一致性:(Consistency)一个事务的完成前后,系统总量仍要保持一致
- 隔离性:(lsolation)多个事务处理同一个数据时,每个事务都应该是隔离开的,防止数据损害
- 持久性:(durability)事务一旦完成,事务的结果都会被保存在持久化容器中
Spring并不会直接管理事务,而是提供了多种事务管理器:
PlatformTransactionManager
这个接口是Spring中的事务管理器,它里面提供了我们常用的操作事务的方法,
-
获取事务的状态信息:
-
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
-
-
提交事务:
-
void commit(TransactionStatus var1) throws TransactionException;
-
-
回滚事务:
-
void rollback(TransactionStatus var1) throws TransactionException;
-
Spring提供了PlatformTransactionManager接口,然而具体的实现还是各大平台(JDBC、Hibernate等)自己来完成的。
DataSourceTransactionManager:JDBC或MyBatis使用(所在包:package org.springframework.jdbc.datasource;)
HibernateTransactionManager:Hibernate使用(所在包:package org.springframework.orm.hibernate5;)
注意上面获取事务信息状态的接口方法getTransaction它的参数是一个TransactionDefinition类型,在这个接口中,就定义了一些基本的事务属性
-
获取事务对象名称:
-
default String getName()
-
-
获取事务的隔离级别
-
default int getIsolationLevel()
-
-
获取事务的传播行为
-
default int getPropagationBehavior()
-
-
获取事务超时时间
-
default int getTimeout()
-
-
获取事务是否只读
-
default boolean isReadOnly()
-
事务的属性我们可以总结为五个方面:传播行为、隔离规则、回滚规则、事务超时、是否只读
Spring的事务传播行为:
spring事务的传播行为指的是:当多个事务同时存在的时候,spring如何处理这些事务的行为。共有七种:
① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
Spring中的隔离级别:
- ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
- ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。
- ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。
- ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。
- ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。
基于XML配置的事务
事务配置相关的标签及其属性:
- 事务配置通知标签 tx:advice
- 属性 id:唯一标识
- 属性 transaction-manager:配置事务管理类的id
- 事务属性配置子标签 tx:attributes
- 子标签事务方法 tx:method
- 属性 name:指定方法的名称,支持通配符*(必须,*表示所有方法)
- 属性 propagation:指定事务的传播行为(默认REQUIRED)
- 属性 isolation:指定事务的隔离级别(默认采用数据库的隔离级别)
- 属性 read-only:指定是否为只读(默认false)
- 属性 timeout:指定事务的超时时间(默认-1永不超时,以秒为单位)
- 属性 no-rollback-for:指定一个异常,设置后,当发生该异常时,事务不会回滚
- 属性 rollback-for:指定一个异常,设置后,当发生该异常时,事务回滚
- 子标签事务方法 tx:method
- aop切面配置子标签 aop:config
- 子标签 aop:advisor:将切入点和事务通知相关联
- 属性 advice-ref:引用通知
- 属性 pointcut-ref:引用切入点
- 子标签 aop:advisor:将切入点和事务通知相关联
只有关键代码,全部流程请参考上一篇(Spring中的AOP)
配置bean.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 添加约束tx-->
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--配置事务管理器 (直接使用jdbc提供的实现类)-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--配置事务的属性-->
<tx:attributes>
<!-- 配置find和get开头的方法传播行为为SUPPORTS(有就在事务中,没有就在非事务中执行),并且设置为只读-->
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<!-- 不属于查询的方法,如增删改,就要保证在事务中进行,并且不为只读-->
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
</tx:attributes>
</tx:advice>
<!--配置aop-->
<aop:config>
<aop:pointcut id="pointcut2" expression="execution(* com.zxy.service.impl.*.*(..))"/>
<!--配置切入点和事务通知关联-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut2"/>
</aop:config>
</beans>
对比上一篇,使用aop,自定义的事务管理类,来完成对事务的控制;到现在我们只需要在xml文件中配置一下,即可实现 让我们的代码在事务中执行
基于注解的事务配置
不光可以使用配置文件的方式,Spring中还提供了注解的方式,比起XML更加简单,使用一个注解,就可以保证方法在事务中运行
@Transactional :
- 使用在接口上:当前接口所有实现类中重写接口的方法有事务的支持
- 使用在类上:当前类中的所有方法有事务的支持
- 使用在方法上:当前方法有事务的支持
(同时出现时的优先级:方法 > 类 > 接口)
在转账的实现类上增加一个注解:
@Transactional
@Override
public void transfer(String name1, String name2, Double money) {
// 获得转账两人信息
Account source = accountMapper.findByName(name1);
Account target = accountMapper.findByName(name2);
source.setMoney(source.getMoney() - money);
target.setMoney(target.getMoney() + money);
// 执行source减少和target增加的更新操作
accountMapper.update(source);
// System.out.println(10 / 0);
accountMapper.update(target);
System.out.println("转账业务完成");
}
@EnableTransactionManagement:开启Spring对注解的支持
在配置类中增加一个注解
···
@EnableTransactionManagement
public class SpringConfig {···
此时使用Spring中为我们提供的两个注解,就完成了事务的功能
当然Transactional注解中也为我们提供了一些属性:
@AliasFor("transactionManager")
String value() default "";// 指定使用的事务管理器
@AliasFor("value")
String transactionManager() default "";
String[] label() default {};
Propagation propagation() default Propagation.REQUIRED;// 指定事务的传播行为
Isolation isolation() default Isolation.DEFAULT;// 指定事务的隔离级别
int timeout() default -1;// 指定事务的超时时间
String timeoutString() default "";
boolean readOnly() default false;// 指定是否为只读
Class<? extends Throwable>[] rollbackFor() default {};// 指定会发生回滚的异常,数组
String[] rollbackForClassName() default {};// 指定会发生回滚的异常的类名,数组
Class<? extends Throwable>[] noRollbackFor() default {};// 指定不会发生回滚的异常,数组
String[] noRollbackForClassName() default {};// 指定不会发生回滚的异常的类名,数组