Spring 学习笔记 Part10
1. Spring 中的事务控制
TX是transaction的缩写。Spring给我们提供了事务控制的API,我们需要导入它的jar包坐标。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
2. 事务控制的API
2.1 PlatformTransactionManager事务管理器
PlatformTransactionManager接口是 spring 的事务管理器,它里面提供了我们3个常用的操作事务的方法。
//获取事务状态信息
TransactionStatus getTransaction(TransactionDefinition definition)
//提交事务
void commit(TransactionStatus status)
//回滚事务
void rollback(TransactionStatus status)
我们在开发中都是使用它的实现类。
//使用 SpringJDBC 或 myBatis 进行持久化数据时使用
org.springframework.jdbc.datasource.DataSourceTransactionManager
//使用 Hibernate版本 进行持久化数据时使用
org.springframework.orm.hibernate5.HibernateTransactionManager
2.2 TransactionDefinition定义信息对象
TransactionDefinition是事务的定义信息对象,有如下方法。
//获取事务对象名称
String getName()
//获取事务隔离级(本节3.1)
String getIsolationLevel()
//获取事务传播行为(本节3.2)
String getPropagationBehavior()
//获取事务超过时间(本节3.3)
String getTimeout()
//获取事务是否只读(本节3.4)
String isReadOnly()
2.3 TransactionStatus事务运行状态
TransactionStatus接口描述了某个时间点上事务对象的状态信息,有6个具体的方法。
//刷新事务
void flush()
//获取事务是否存在存储点
boolean hasSavepoint()
//获取事务是否完成
boolean isCompleted()
//获取事务是否为新的事务
boolean isNewTransaction()
//获取事务是否回滚
boolean isRollbackOnly()
//设置事务回滚
void setRollbackOnly()
事务中的Savepoints :
你可以在事务上下文中声明称为savepoint的中间标记。
Savepoint将一个长事务分隔为较小的部分。 使用savepoint,你可以在长事务中任何点任意标记你的操作。成功执行到存储点时,存储点会保存,成功执行完所有语句时,事务结束。你可以选择回滚在事务中当前点之前、声明的savepoint之后执行的操作。比如,你可以在一长段复杂的更新中使用savepoint,如果犯了个错,你不需要重新提交所有语句。
3. 事务定义信息对象的属性
定义信息对象,class TransactionDefinition,是Spring提供的一个API(本节2.2介绍)
3.1 事务的隔离级别
事务隔离级别反应事物提交并发访问时的处理态度。
//默认级别,归属下列某一种(数据库默认配置)
ISOLATION_DEFAULT
//可以读取未提交数据
ISOLATION_READ_UNCOMMITTED
//只能读取已经提交的数据,解决了脏读的问题 (Oracle默认级别)
ISOLATION_READ_COMMITTED
//只能读取其他事物提交修改后的数据,解决了不可重复读的问题(Mysql默认级别)
ISOLATION_REPETABLE_READ
//只能读取其他事物提交添加后的数据,解决幻读的问题
ISOLATION_SERIALIZABLE
3.2 事务的传播行为
事务的传播行为反应了什么情况下一定要有事务和什么情况可有可没有。
REQUIRED //如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
SUPPORTS //支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
MANDATORY //使用当前的事务,如果当前没有事务,就抛出异常
REQUERS_NEW //新建事务,如果当前在事务中,把当前事务挂起。
NOT_SUPPORTED //以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER //以非事务方式运行,如果当前存在事务,抛出异常
NESTED //如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。
通常情况下,增删改使用REQUIRED(有就加入,没有就创建,到最后一定会有事务),查使用SUPPORTS(有就用,没有就拉倒)
3.3 超过时间
默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
3.4 是否是只读事务
读写型事务:增加、删除、修改会开启事务
只读型事务:执行查询时,也会开启事务
建议查询时设置为只读。
4. 基于XML的声明式事务控制的配置
spring中基于XML的声明式事务控制配置步骤共有 5 步:
第 1 步、配置事务管理器
第 2 步、配置事务的通知
第 3 步、配置AOP中的通用切入点表达式
第 4 步、建立事务通知和切入点表达式的对应关系
第 5 步、配置事务的属性
第 1 步、配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
第 2 步、配置事务的通知
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 标签体内用于配置事务的属性 -->
</tx:advice>
第 3 步、配置AOP中的通用切入点表达式
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"/>
</aop:config>
第 4 步、建立事务通知和切入点表达式的对应关系
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
</aop:config>
切入点表达式和切入点对应关系都要配置在< aop:config >标签里。
在此我们可以发现,有了spring提供的事务管理器,我们在< aop:config >标签里就用不着配置< aop:aspect >标签了(配置在前在后异常通知的标签),因为事务管理器都为我们做好了。
第 5 步、配置事务的属性
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/> //有事务就加入,没事务就创建,一定会有事务。不只读(可写)。
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/> //有事务就有,没有就拉倒。只读。
//表示find*开头的方法。范围比*小,故优先级比*高
</tx:attributes>
</tx:advice>
配置事务的属性:
isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值,没值的时候表示任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值,没值的时候表示任何异常都回滚。
到此为止,execution(* com.itheima.service.impl..(…))表达式所包含的那个service文件夹下的就已经有了事务控制了,再也没有事务的问题干扰我们了。