Spring的事务

什么是事务?

保证业务操作完整性的一种数据库机制

事务的四大特定:ACID

A :原子性:

原子性确保一个事务中的所有操作要么全部成功,要么全部失败。如果事务的任何部分失败,整个事务将被回滚到初始状态,不会留下部分更改。这意味着事务是不可分割的单元,要么完全执行,要么完全不执行。

C : 一致性

一致性确保事务将数据库从一个一致的状态变为另一个一致的状态。在事务开始和结束时,数据库必须满足一组预定义的规则(业务规则、约束等)。如果事务执行过程中违反了这些规则,事务将被回滚。

I : 隔离性

隔离性确保多个事务同时执行时,每个事务都不会受到其他事务的影响。每个事务都应该以一种独立的方式执行,就好像其他事务不存在一样。这防止了并发事务之间可能出现的问题,如脏读、不可重复读和幻读。 D: 持久性

持久性确保一旦事务成功提交,其结果将在数据库中永久存储,即使在系统发生故障或重启后也不会丢失。这通常涉及将事务的更改写入稳定的存储介质(如硬盘)。

如何来控制事务

JDBC:

Connection.setAutoCommit(false);

Connection.commit();

Connection.rollback();

Mybatis:

Mybatis自动开启事务(sqlSession底层封装了Connection)

sqlSession.commit();

sqlSession.rollback();

结论:

控制事务的底层都是Connection对象完成的

Spring控制事务开发

  • Spring是通过AOP的方式进行事务开发的
  1. 原始对象
kotlin 复制代码
public class XXXUserServiceImpl{
	private xxxDAO xxxDAO;
 set /get
	1.原始对象--->原始方法--->核心功能(业务处理+DAO调用)
  2. DAO 作为Service的成员变量,通过依赖注入的方式赋值
}
  1. 额外功能(事务)
scss 复制代码
Spring封装了这个事务(DataSoureceTranactionManager)
我们要为它注入Connection  ===注入连接池


1.MethodInterceptor

invoke(MehodInvocation invocation){
    try {
    Connection.setAutoCommit(false)
    Object ret=invocation.proceed();
	Connection.commit();
	}catch(Excetion e){
    Connection.rollback();
	}	
	return ret;
}

2.@Aspect
  1. 切入点
markdown 复制代码
@Transational
事务的额外功能加给哪些业务方法

1. 类上:这个类中,所以的方法加入事务
2. 方法上:这个方法会加入事务
   
  1. 切面

<tx:annotiaion-driven transaction-manager=""/>

Spring控制事务的编码

  • 搭建开发环境
xml 复制代码
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>6.0.8</version>
        </dependency>
xml 复制代码
    <bean id="userService" class="com.huy.service.UserServiceImpl">
        <property name="userDAO" ref="userDAO"></property>
    </bean>
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSourse"></property>
    </bean>
    <!--组合切入点和事务-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

Spring中的事务属性

1. 什么是事务属性

描述物体特征的一系列值

事务属性:描述事务特征的一系列值

  1. 隔离属性
  2. 传播属性
  3. 只读属性
  4. 超时属性
  5. 异常属性

2. 如何添加事务属性

ini 复制代码
@Transactional(isloation= ,propagation= ,redaOnly= ,timeout= ,
                   rollbackFor=,noRollbackFor=)

3. 事务属性详解

3.1. 隔离属性

概念:它描述了事务解决并发问题的特征

  1. 什么是并发

多个事务或者用户在同一时间,访问或操作了相同数据

同一时间:0.000几秒的 微小前 微小后的差异

  1. 并发产生的哪些问题
    1. 脏读
    2. 不可重复读
    3. 幻读
  1. 并发问题如何解决
    1. 通过隔离属性来解决,隔离属性设置不同的值,处理并发处理过程中的问题
  • 事务并发的问题

脏读:

指的是,一个事务读取了另一个事务没有提交的数据。会在事务中产生数据不一致的问题

账户本来有1000块,suns媳妇先去取了700,但没提交,这时候suns取取钱,发现里面是700,取了 200,但suns媳妇最后回滚了,suns取钱提交了,这时候账户就只剩500了,少了300块钱。这就是

一个事务读取到另一个事务还没提交的事务,产生数据不一致的问题

解决方案:

@Transactional(isolation=Isolation.READ.COMMITTED)

改为读已提交

不可重复读:

指的是:一个事务中,多次读取相同数据,但是读取结果不一样。会在事务中产生数据不一致的问题

suns媳妇开启事务,先查询了余额1000,然后进行一系列操作,suns这时候取了200,并且已经提交,这时候suns媳妇又查询了余额发现为800,两次读取余额不一致

注意:1 不是脏读 2 他是在一个事务中读了两次不一样

解决方案: @Transactional(isolation=Isolation.REPEATABLE_TABLE)

本质:一把行锁

也就是suns媳妇开启了事务操作那一行数据的时候,suns去操作那行数据,就得登suns媳妇提交事务才能去操作,这样suns媳妇拿到的数据就会是一致的

幻影读:

一个事务中,多次对整表进行查询统计,但是结果不一样,会在本事务中产生的数据不一致的问题

解决方案:

@Transactional(isolation=Isolation.SERIALIZEABLE)

本质:数据库底层的表锁

t1统计表的时候,给整表加上表锁,只有等t1提交事务,t2才能进行操作

  • 总结

并发安全: SERIALIZABLE>REPEATABLE_READ>READ_COMMITTED

运行效率: SERIALIZABLE<REPEATABLE_READ<READ_COMMITTED

  • 数据库对于隔离属性的支持
  • 默认的隔离属性

ISOLATION_DEFAULT:会调用不同数据所设置的默认隔离属性

MYSQL: REPEATABLE_READ

Oracle: READ_COMMITTED

查看你默认隔离属性

MySQL:

SELECT @@global.transaction_isolation;

Oracle:

  • 隔离属性推荐实战中

推荐使用Spring指定的默认隔离级别

MySQL :repeatable_read 可重复读

如果真遇到并发的问题,我们会通过乐观锁

Hibernate(JPA) Version

Mybatis 通过拦截器自定义开发

3.2. 传播属性

  • 概念

描述了事务解决嵌套问题的特征

什么是事务的嵌套

它指的是一个大的事务其中包含一个小的事务

问题: 大事务中融入了很多小的事务,他们彼此影响,最终就会导致外部大的大事务,失去了事务的原子性。

  • 传播属性的值以及其用法
less 复制代码
@Transactional(Propagation=Propagation.REQUIRED)
REQUIRED
1. 外部不存在事务,开启新的
2. 外部存在事务,融合
一般增删改方法使用这个传播属性,REQUIRED

@Transactional(Propagation=Propagation.SUPPORTS)
SUPPORTS
1. 外部不存在事务,不开启事务
2. 外部存在事务 融合
一般会运用在查询方法中,SUPPORTS
  • 默认的传播属性

REQUIRED是传播属性的默认值

  • 推荐传播属性的使用方法

增删改:使用默认值 REQUIED

查询: 操作:显示的指定传播属性的值为SUPPORTS

  • 其他传播属性

REQUIREDS_NEW 外部不存在事务,开启新事务,

外部存在事务,挂起外部事物,开启新的事务,

新的事务执行完后,在执行外部事务

3.3. 只读属性(readOnly)

针对于只进行查询操作的业务方法,可以加入只读属性,提供运行效率

@Transation(readOnly=true)

默认值 false

所以在查询操作的过程中就加上只读属性

3.4. 超时属性(timeout)

指定了事务等待的最长时间

  1. 为什么事务进行等待?

当前事务访问数据时,有可能访问的数据被其他的事务进入加锁的处理,那么此时本事务就必须等待

  1. 等待时间 秒
  2. 如何使用

@Transation(timeout=2)

  1. 超时属性的默认值 -1

最终由对应的数据来指定

3.5. 异常属性

Spring事务处理过程中

默认 对于RuntimeException以及其子类 采用的是回滚的策略

对于Exception以及其子类 采用的是提交的策略

rollbackFor ={java.lang.Exception.class} 抛出.Exception回滚

noRollbackFor={java.lang.RuntimeException.class} 抛出RuntimeException提交

建议:实战中使用RuntimeException回滚,也就是spring默认的异常属性

4. 事务属性常见配置总结

  1. 隔离属性 默认值
  2. 传播属性 REQUIRED(默认值) 增删改 Supports 查询操作
  3. 只读属性 readOnly 默认 false 查询操作 true
  4. 超时属性 timeout -1
  5. 异常属性 默认值 RuntimeException 回滚 Exception 提交

增删改操作 @Transactional

查询操作 @Transactional(propagation=supports,redaOnly=true)

相关推荐
黄俊懿1 分钟前
【深入理解SpringCloud微服务】手写实现各种限流算法——固定时间窗、滑动时间窗、令牌桶算法、漏桶算法
java·后端·算法·spring cloud·微服务·架构
2401_8574396928 分钟前
“衣依”服装销售平台:Spring Boot技术应用与优化
spring boot·后端·mfc
Jerry.ZZZ1 小时前
系统设计,如何设计一个秒杀功能
后端
九圣残炎2 小时前
【springboot】简易模块化开发项目整合Redis
spring boot·redis·后端
.生产的驴3 小时前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
爱学的小涛3 小时前
【NIO基础】基于 NIO 中的组件实现对文件的操作(文件编程),FileChannel 详解
java·开发语言·笔记·后端·nio
爱学的小涛3 小时前
【NIO基础】NIO(非阻塞 I/O)和 IO(传统 I/O)的区别,以及 NIO 的三大组件详解
java·开发语言·笔记·后端·nio
北极无雪3 小时前
Spring源码学习:SpringMVC(4)DispatcherServlet请求入口分析
java·开发语言·后端·学习·spring
爱码少年3 小时前
springboot工程中使用tcp协议
spring boot·后端·tcp/ip
2401_8576226611 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php