spring声明事务
事务
在一次业务操作中的所有增删改都应该都成功,要么都失败
如果其中的一次操作执行失败,则应该回滚到没执行的状态
事务的四大特性
事务特性 | 含义 |
---|---|
原子性(Atomicity) | 事务是工作的最小单元,整个工作单元要么全部执行成功,要么全部执行失败 |
一致性(Consistency) | 事务执行前与执行后,数据库中数据应该保持相同的状态。如:转账前总金额与转账后总金额相同。 |
隔离性(Isolation) | 事务与事务之间不能互相影响,必须保持隔离性。 |
持久性(Durability) | 如果事务执行成功,对数据库的操作是持久的。 |
事务并发访问的问题
-
脏读: 一个事务(用户)读取到了另一个事务没有提交的数据
-
不可重复读:当别人的事务修改提交了数据后,在我们的事务中在修改前和修改后查询出现了不同的数据
-
幻读:在一次事务中,多次读取到的条数不一致
事务的隔离级别
级别 | 名字 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 数据库默认隔离级别 |
---|---|---|---|---|---|---|
1 | 读未提交 | read uncommitted | 是 | 是 | 是 | |
2 | 读已提交 | read committed | 否 | 是 | 是 | Oracle和SQL Server |
3 | 可重复读 | repeatable read | 否 | 否 | 是 | MySQL |
4 | 串行化 | serializable | 否 | 否 | 否 |
可重复读会触发幻读的两种情况:在我方事务进行修改后再查询会出现另一方的数据
在我方插入的数据与另一方提交插入的数据主键冲突时会插入失败
串行化:把读取的数据或者修改的数据加上读锁或写锁
(根据主键列作为索引会触发行锁,非主键列作为索引会触发表锁)
当一方事务在读的过程中,另一方事务无法进行写操作
当一方事务在写的过程中,另一方事务无法进行读写操作(Ctrl+C停止)
查询事务隔离级别
select @@tx_isolation;
设置事务隔离级别(需要重启客户端会话)
set global transaction isolation level 四种隔离;
set global transaction isolation level read uncommitted;
set global transaction isolation level read committed;
set global transaction isolation level repeatable read;
set global transaction isolation level serializable;
开启事务
start transaction;
或者
begin;
提交事务
commit;
回滚事务
rollback;
Spring事务管理
编程式事务(不符合高内聚低耦合)
将事务管理代码写入到业务方法中,对核心业务代码的侵入性太大
可以以代码块的级别开启事务
声明式事务
AOP非常适合管理事务,通过声明表达式拦截需要事务管理的方法
声明式事务避免了对核心事务的入侵
不足:开启事务的级别最细的级别只能做到方法级别,无法做到编程式的代码块级别
Spring事务管理器
所有的事务管理器的都继承自org.springframework.transaction.PlatformTransactionManager
接口。
-
事务管理器主要的实现:
-
DataSourceTransactionManager
:使用Spring JDBC 或 Mybatis 等基于DataSource数据源的持久化技术时,使用 该事务管理器 -
JpaTransactionManager
:使用JPA时采用的事务管理器 -
JtaTransactionManager
:具有多个数据源的全局事务使用该事务管理器 -
JdoTransactionManager
:使用JDO进行持久化时 ,使用该事务管理器 -
HibernateTransactionManager
:使用Hibernate进行持久化时,使用该事务管理器
事务传播行为
Spring定义了7种类传播行为,在org.springframework.transaction.TransactionDefinition
类中被定义。
静态常量 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择,也是Spring的默认值。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
TransactionDefinition
类中不仅定义了事务的传播行为,也定义了很多事务的隔离级别:
静态常量 | 说明 |
---|---|
ISOLATION_DEFAULT | 使用数据库默认的隔离级别,Spring默认值 |
ISOLATION_READ_UNCOMMITTED | 读未提交 |
ISOLATION_READ_COMMITTED | 读已提交 |
ISOLATION_REPEATABLE_READ | 可重复读 |
ISOLATION_SERIALIZABLE | 串行化 |
实现事务管理器
默认是:编译式异常不会回滚,运行式异常会回滚
XML
配置事务管理器及事务通知
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--引用数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
isolation:事务隔离级别
DEFAULT:使用数据库默认的隔离级别(默认值)
READ_UNCOMMITTED:读未提交
READ_COMMITTED:读已提交
REPEATABLE_READ:可重复读
SERIALIZABLE:串行化
propagation: 事务传播行为
REQUIRED:必须要有事务,如果已经存在事务,则加入到这个事务中,如果没有事务则创建一个新的事务
SUPPORTS:支持当前事务,如果调用这个方法之前没有事务则不会开启新的事务
MANDATORY:必须存在事务,如果调用此方法之前没有事务,就抛出异常
REQUIRES_NEW:新建事务,如果调用此方法之前就已经开启过事务,则将之前的事务挂起
NOT_SUPPORTED:非事务方式,如果调用此方法之前就存在事务,则挂起事务
NEVER:非事务方式运行,如果调用此方法之前存在事务,则抛出异常
NESTED:如果存在事务,则嵌套在事务内执行,如果没有事务则与REQUIRED保存一致
read-only: 是否只读
true: 只读
false:非只读(默认值)
timeout: 方法执行超时时间,默认值为-1,代表永不超时,单位为秒
rollback-for: 指定特定的异常才回滚(默认情况下,任何的运行时异常事务都会回滚,但编译时异常都不会进行回滚),该配置针对于编译时异常;可以写多个,以逗号隔开
no-rollback-for: 指定一个特定的异常事务不回滚,可以写多个,以逗号隔开
-->
<!-- <tx:method name="query*" isolation="DEFAULT"
propagation="REQUIRED" read-only="true" timeout="3"
rollback-for="java.lang.NullPointerException,java.lang.ClassCastException"
no-rollback-for="java.lang.ArithmeticException" />
-->
<!-- <tx:method name="query*" read-only="true"/>-->
<!-- <tx:method name="select*" read-only="true"/>-->
<!-- <tx:method name="query*" read-only="true"/>-->
<!-- <tx:method name="save*" read-only="true"/>-->
<!-- <tx:method name="insert*" />-->
<!-- <tx:method name="add*" />-->
<!-- <tx:method name="update*" />-->
<!-- <tx:method name="modify*" />-->
<!-- <tx:method name="delete*" />-->
<!-- <tx:method name="remove*" />-->
<!--出现ArithmeticException异常不回滚-->
<tx:method name="transfer" no-rollback-for="java.lang.ArithmeticException"/>
</tx:attributes>
</tx:advice>
-
no-rollback-for
:指定什么异常不回滚(该配置只针对于运行时异常),可以写多个,以逗号隔开;-
no-rollback-for
指定的参数是Exception
:则代表Java中的任何异常都不回滚,
-
-
rollback-for
:指定什么异常要回滚(该配置针对于编译时异常);可以写多个,以逗号隔开;-
rollback-for
指定的参数是Exception
:则Java中任何的异常都回滚;
-
开启事务注解驱动
<!--
开启事务注解驱动
transaction-manager: 指定事务管理的名称,默认为transactionManager
-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
注解
配置事务管理器及事务通知
@Transactional(
transactionManager = "transactionManager", // 事务管理器的名称
propagation = Propagation.REQUIRED, // 传播行为
isolation = Isolation.DEFAULT, // 隔离级别
timeout = 3000, // 超时时间
readOnly = false, // 是否只读
rollbackFor = {MyException.class}, // 出现该异常回滚
noRollbackFor = {ArithmeticException.class} // 出现指定异常不回滚
)
作用范围:
-
可以添加在方法上,对特定的方法开启事务管理。
-
也可以添加在类级别上,此时该类中的所有 public 方法都会被事务管理。
开启事务注解驱动
@EnableTransactionManagement
它告诉 Spring 容器开启对声明式事务的支持。当在 Spring 配置类上添加了这个注解后,Spring 会自动扫描被@Transactional
注解标记的方法和类,并为它们提供事务管理功能。
Spring 在启动时会解析带有@EnableTransactionManagement
注解的配置类,并根据配置创建事务管理器和事务拦截器。事务拦截器会拦截被@Transactional
注解标记的方法调用,在方法执行前后进行事务的开启、提交或回滚操作。
一、mode 属性
-
作用:用于指定事务管理的模式。
-
可选值:
-
AdviceMode.PROXY
(默认值):使用代理模式实现事务管理。Spring 会为被@Transactional
注解的目标对象创建一个代理对象,在代理对象中拦截方法调用并进行事务处理。这是最常用的模式,适用于大多数情况。 -
AdviceMode.ASPECTJ
:使用 AspectJ 实现事务管理。这种模式需要在项目中引入 AspectJ 相关的库,并进行额外的配置。AspectJ 方式可以在不使用代理的情况下实现事务管理,对于某些复杂的场景可能更有优势,但配置相对复杂一些。
-
二、order 属性
-
作用:用于指定事务通知在 Spring AOP 通知链中的顺序。
-
说明:当有多个 AOP 通知(如事务通知、安全通知等)同时存在时,通过设置
order
属性可以控制它们的执行顺序。较小的值表示较高的优先级,即先执行。
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
@Configuration
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ, order = 1)
public class AppConfig implements TransactionManagementConfigurer {
// 其他配置...
}