Spring事务管理

一、什么是事务

       在实际开发中,操作数据库时都会涉及到事务管理问题,为此Spring提供了专门用于事务处理的API。Spring的事务管理简化了传统的事务管理流程,并且在一定程度上减少了开发者的工作量。事务由单独单元的一个或者多个sql语句组成。

二、事务管理的核心接口

        在Spring的所有JAR包中,包含一个名为spring-tx-5.3.9的JAR包,该包就是Spring提供的用于事务管理的依赖包。在该JAR包的org.springframework.transaction包中,有3个接口文件PlatformTransactionManager、TransactionDefinition和TransactionStatus

        1、Platform TransactionManager:

         PlatformTransactionManager接口是Spring提供的平台事务管理器,主要用于管理事务。该接口中提供了三个事务操作的方法,具体如下:

        2、TransactionDefinition

        TransactionDefinition接口是事务定义(描述)的对象,该对象中定义了事务基本属性,并提供了获取事务基本属性的方法,具体如下:

        3、TransactionStatus

        TransactionStatus接口是事务的状态,它描述了某一时间点上事务的状态信息。该接口中包含6个方法,具体如下

三、事务的管理方式

        事务的管理方式一般分为两种:第一种是编程式事务管理(通过编写代码实现的事务管理)。第二种是声明式事务管理(通过XML配置或注解的方式实现的事务管理)。

编程式事务管理:

步骤1:添加事务管理器组件,在applicationContext.xml中配置一个事务管理器组件,提供对事务处理的全面支持和统一管理

<!--定义事务管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

步骤2:在业务逻辑类中使用事务管理器,在AccountService中使用事务管理器,完成依赖注入

@Service
public class AccountService {

@Autowired
private AccountDao accountDao;

@Autowired
private PlatformTransactionManager txManager;

//转账操作方法

}

步骤3:在方法中编程实现事务管理,在moneyTransfer方法中,使用事务管理器编写代码事务的提交或回滚

//定义事务规则(隔离级别、传播行为)
DefaultTransactionDefinition definition=new DefaultTransactionDefinition();
//开启事务管理,并返回事务状态
TransactionStatus status = txManager.getTransaction(definition);
try {
	//转账业务逻辑(省略)
	txManager.commit(status); //提交事务
} catch (Exception e) {
	txManager.rollback(status); //如果出现异常回滚事务
}

但是编程式事务管理必须要在业务逻辑中包含额外的事务管理代码。和业务逻辑代码产生了耦合,产生了代码冗余,不方便代码的维护和扩展。而声明式事务管理最大的优点在于开发者无需通过编程的方式来管理事务,只需在配置文件中进行相关的事务规则声明,就可以将事务应用到业务逻辑中。

声明式事务管理(基于XML的方式):

基于XML方式的声明式事务是在配置文件中通过<tx:advice>元素配置事务规则来实现的,然后通过使用<aop:config>编写的AOP配置,让Spring自动对目标生成代理。

步骤1:添加事务管理器组件,在applicationContext.xml中配置一个事务管理器组件,提供对事务处理的全面支持和统一管理。

<!--定义事务管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

步骤2:使用<tx:advice>标签配置事务规则,修改applicationContext.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
       https://www.springframework.org/schema/tx/spring-tx.xsd">

使用<tx:advice>标签进一步对事务管理器配置事务规则

<!-- 配置事务规则 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 定义哪些方法需要进行事务处理,*表示任意字符 -->
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="moneyTransfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>

步骤3:使用<aop:config>配置事务切面,并应用事务规则基于注解方式的声明式事务

<!-- 定义切面 -->
<aop:config>
<!-- 定义切点范围 -->
<aop:pointcut expression="execution(* service.*.*(..))" id="pointcut"/>
<!-- 应用事务规则 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
声明式事务管理(基于注解方式)

步骤1:配置事务管理器在applicationContext.xml中配置一个事务管理器组件,提供对事务处理的全面支持和统一管理

<!--定义事务管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

步骤2:注册事务注解驱动

<!-- 注册事务注解驱动 -->
<tx:annotation-driven transaction-manager="txManager"/>

 步骤3:注册事务注解驱动,在需要事务管理的类或方法上使用@Transactional注解

@Transactional
public String moneyTransfer(String accountA, String accountB, double money) {
	//业务逻辑代码
}

四、事务的四大特性

事务有四大特性,简称ACID。

原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。                                                                                                             例子:假设你要将10000从你的账户转到朋友的账户。在转账过程中,如果出现任何错误,比如网络连接中断或者账户余额不足,那么整个转账过程将会被回滚,你的账户不会被扣款,同时朋友的账户也不会收到钱。

一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保他所建模的业务处于一致的状态,而不会是部分完成部分失败。现实中的数据不应该被破坏。                                 例子:假设你从一个银行账户转账到另一个银行账户。在转账过程中,数据库会记录这次转账的信息,并在转账成功后更新账户余额。如果在转账过程中发生错误,比如网络中断,那么数据库会回滚到事务开始前的状态,保持数据的一致性。

隔离性(Isolation):可能会有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。                                                                                                             例子:假设有两个人同时进行转账操作,一个从账户A转账到账户B,另一个从账户B转账到账户C。在并发执行的过程中,事务隔离性确保了每个转账操作相互独立,不会出现数据混乱或者冲突的情况。

持久性(Durability):一旦事务完成,无论发生什么系统错误,他的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。               例子:当你进行一笔转账并成功提交后,该笔转账的结果将会永久保存在数据库中,即使后续发生了系统故障,你的转账记录也不会丢失。

五、事务隔离级别

隔离级别

1、ISOLATION_DEFAULT:使用后端数据库默认的隔离级别

2、ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读仍有可能复读。

3、ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。

4、ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务所修改,可以阳止脏读和不可重复读,但幻读仍有可能发生,

5、ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从 ACID 的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现。

隔离级别可能会导致的问题

1、脏读(Dirty reads):脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了。那么第一个事务获取的数据就是无效的。
2、不可重复读(Nonrepeatable read):不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
3、幻读(Phantom read):幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会
发现多了一些原本不存在的记录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值