浅谈Spring6之事务场景(注解方式)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 事物:在一个业务流程中,通常需要多条DML(insert delete update)语句共同联合才能完成的,为了保证数据的安全,多条DML语句都必须同时成功,,或同时失败。

事物:在一个业务流程中,通常需要多条DML(insert delete update)语句共同联合才能完成的,为了保证数据的安全,多条DML语句都必须同时成功,,或同时失败。


事物的四个处理过程:开启事务、执行核心业务代码、提交事务、回滚事务


事务的四个特性:


原子性:事务是最小工作单位,不可再分割


一致性:事务要么同时成功,要么同时失败。事务前和事务后的总量不变


隔离性:事务和事务之间有隔离性,互不干扰


持久性:持久性是事务结束的标志


Spring实现事务的两种方式


编程式事务:编写代码来实现事务的管理


声明式事务*:基于注解的方式、基于xml配置方式



如有错误请指正,谢谢


以银行账户转账为案例

数据库表


12.png


spring6整合mybatis


pom.xml配置文件

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

   4.0.0

   org.example

   spring6-transaction-bank

   1.0-SNAPSHOT

   

       17

       17

       UTF-8

   

   

   jar

   

   

       

       

           repository.spring.milestone

           Spring Milestone Repository

           https://repo.spring.io/milestone

       

   

   

   

       

           jakarta.annotation

           jakarta.annotation-api

           2.1.0

       

       

       

           org.springframework

           spring-context

           6.0.0-M2

       

       

       

           org.springframework

           spring-jdbc

           6.0.0-M2

       

       

       

           mysql

           mysql-connector-java

           8.0.17

       

       

       

           org.mybatis

           mybatis

           3.5.11

       

       

       

       

           org.mybatis

           mybatis-spring

           3.0.1

       

       

       

           com.alibaba

           druid

           1.2.15

       

       

       

           org.springframework

           spring-test

           6.0.0-M2

           

       

       

       

           org.junit.jupiter

           junit-jupiter-api

           5.8.2

           test

       

   

   

       

           

               

               src/main/java

               

                   

                   **/*.properties

                   **/*.xml

               

               false

           

       

   



jdbc.properties文件

jdbc.driver=com.mysql.cj.jdbc.Driver

jdbc.url=jdbc:mysql://IP:3306/mysql

jdbc.user= root

jdbc.password= xxxxxx

mybatis-config.xml配置文件


       PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

       "https://mybatis.org/dtd/mybatis-3-config.dtd">

   

       

       

   

   

       

   



SpringConfig.xml配置文件

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xmlns:context="http://www.springframework.org/schema/context"

      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/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd">

       

       

       

       

       

       

               

               

               

               

       

       

       

               

               

               

               

               

               

       

               

       

               

               

       

               

       

               

       

               

       



BankDao接口

public interface BankDao {

   /**

    * 根据账号查询账户信息

    */

   List selectAll();

   /**

    * 根据actno查询账户信息

    * @param actno

    * @return

    */

   Bank selectByActno(String actno);

   /**

    * 更新账户信息

    * @param act

    * @return

    */

   int update(Bank act);

}


BankDao.xml


       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

       "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

           select * from bank    

           select actno,balance from bank where actno = #{actno}    

   

       update bank set  balance=#{balance}  where actno =#{actno}

   



pojo实体类

package com.qgs.pojo;

/**

* @author QGS

* @version 1.0.0

* @date 2023年03月24日 16:36:58

* @packageName com.qgs.pojo

* @className Bank

* @describe TODO

*/

public class Bank {

   private String actno;

   private Double balance;

   public Bank() {

   }

   public Bank(String actno, Double balance) {

       this.actno = actno;

       this.balance = balance;

   }

   public String getActno() {

       return actno;

   }

   public void setActno(String actno) {

       this.actno = actno;

   }

   public Double getBalance() {

       return balance;

   }

   public void setBalance(Double balance) {

       this.balance = balance;

   }

   @Override

   public String toString() {

       return "Bank{" +

               "actno='" + actno + '\'' +

               ", balance=" + balance +

               '}';

   }

}


BankService 接口

public interface BankService {

   /**

    * 转账方法

    * @param fromActno 转出账户

    * @param toActno 转入账户

    * @param money 金额

    */

   void transfer(String fromActno ,String toActno ,double money);

}

BankService 接口实现类

package com.qgs.service;

import com.qgs.dao.BankDao;

import com.qgs.pojo.Bank;

import jakarta.annotation.Resource;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Propagation;

import org.springframework.transaction.annotation.Transactional;

/**

* @author QGS

* @version 1.0.0

* @date 2023年03月25日 11:15:24

* @packageName com.qgs.service

* @className BankServiceImpl

* @describe TODO

*/

@Service("bankServiceImpl")

//@Transactional

public class BankServiceImpl implements BankService{

   @Resource(name ="bankDao")

   private BankDao bankDao;

   @Override

   //@Transactional默认propagation = Propagation.REQUIRED

   @Transactional(propagation = Propagation.REQUIRED)

   public void transfer(String fromActno, String toActno, double money) {

       //查询转出账户余额

       Bank fromBank = bankDao.selectByActno(fromActno);

       if (fromBank.getBalance()

           throw new RuntimeException("余额不足");

       }

       //查询转入账户余额

       Bank toBank = bankDao.selectByActno(toActno);

       //将内存中转出与转入账户余额修改

       fromBank.setBalance(fromBank.getBalance() - money);

       toBank.setBalance(toBank.getBalance() + money);

       //更新数据库

       int count = bankDao.update(fromBank);

       int count2 = bankDao.update(toBank);

       count +=count2;

       if (count !=2){

           //回滚事务,转账失败

           throw new RuntimeException("失败");

       }

   }

}


@Test

   public void BankTest(){

       ApplicationContext applicationContext =new ClassPathXmlApplicationContext("SpringConfig.xml");

       BankService bankService = applicationContext.getBean("bankServiceImpl", BankService.class);

       try {

           bankService.transfer("act01","act2",300);

       }catch (Exception e){

           e.printStackTrace();

       }

   }

11.png


事务的传播行为


7.png8.png9.png





事务传播行为在spring框架中被定义为枚举类型。

事务的传播行为有7种:

REQUIRED:支持当前事务,如果不存在就新建一个(默认模式)

SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常。

REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起。

NOT_SUPPORTED:以非事务方式运行,如果事务存在,挂起当前事务。

NEVER:以非事务方式运行,如果有事务存在,抛出异常。

NESTED:如果当前争优一个事务在进行中,则该方法应当运行一个嵌套事务中。被嵌套的事务可以单独于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED。


数据库中读取数据存在的三大问题


脏读:读取到没有提交的数据库的数据。


不可重复读:在同一个事务当中,第一次和第二次读取的数据不一样。


幻读:读到的数据是假的。(事务并发,一定存在幻读)


spring事务隔离级别


5.png6.png




数据库中读取数据存在的三大读问题

脏读:读取到没有提交的数据库的数据。

不可重复读:在同一个事务当中,第一次和第二次读取的数据不一样。

幻读:读到的数据是假的。(事务并发,一定存在幻读)


事务隔离级别的四个级别:

读未提交:READ_UNCOMMITTEN

   这种隔离级别:存在脏读问题,所谓的脏读(dirty read)表示能够读取到其他事务未提交的数据。

读提交:READ_COMMITTED        (oracle)

   解决了脏读问题,其他事务提交之后才能读到,但存在不可重复读问题

可重复读:REPEATABLE_READ     (MYSQL)

   解决了不可重复读,可以达到可重复读效果,只要当前事务不结束,读取到的数据移植都是一样的。但存在幻读问题。

序列化:SERIALLZABLE

   解决了幻读问题,事务排毒执行。不支持并发。

4.png



Spring事务超时

@Transactional(timeout = 10)   表示设置事务的超时时间为10秒。


超过10秒如果该事务所有的DML语句还没有执行完毕,最终选择回滚。

在当前事务中,最后一条DML语句执行之前的时间。最后一条DML语句后面还有很多业务逻辑(非DML语句),这些业务代码执行的时间不被记入超时时间

默认值为:timeout = -1 、表示没有时间限制。

3.png



Spring启动只读事务

@Transactional(readOnly = true)  作用:启动Spring优化策略,提高select语句执行效率

2.png


Spring事务设置异常回滚问题

设置RuntimeException异常时回滚

@Transactional(rollbackFor = RuntimeException.class)

设置NullPointerException异常不回滚

@Transactional(noRollbackFor = NullPointerException.class)


1.png


1.png

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
2月前
|
缓存 监控 Java
SpringBoot @Scheduled 注解详解
使用`@Scheduled`注解实现方法周期性执行,支持固定间隔、延迟或Cron表达式触发,基于Spring Task,适用于日志清理、数据同步等定时任务场景。需启用`@EnableScheduling`,注意线程阻塞与分布式重复问题,推荐结合`@Async`异步处理,提升任务调度效率。
505 128
|
2月前
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
2月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
405 0
|
1月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
347 2
|
2月前
|
XML Java 数据格式
常用SpringBoot注解汇总与用法说明
这些注解的使用和组合是Spring Boot快速开发和微服务实现的基础,通过它们,可以有效地指导Spring容器进行类发现、自动装配、配置、代理和管理等核心功能。开发者应当根据项目实际需求,运用这些注解来优化代码结构和服务逻辑。
287 12
|
2月前
|
Java 测试技术 数据库
使用Spring的@Retryable注解进行自动重试
在现代软件开发中,容错性和弹性至关重要。Spring框架提供的`@Retryable`注解为处理瞬时故障提供了一种声明式、可配置的重试机制,使开发者能够以简洁的方式增强应用的自我恢复能力。本文深入解析了`@Retryable`的使用方法及其参数配置,并结合`@Recover`实现失败回退策略,帮助构建更健壮、可靠的应用程序。
321 1
使用Spring的@Retryable注解进行自动重试
|
2月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
529 5
|
2月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
178 0
探索Spring Boot的@Conditional注解的上下文配置
|
2月前
|
智能设计 Java 测试技术
Spring中最大化@Lazy注解,实现资源高效利用
本文深入探讨了 Spring 框架中的 `@Lazy` 注解,介绍了其在资源管理和性能优化中的作用。通过延迟初始化 Bean,`@Lazy` 可显著提升应用启动速度,合理利用系统资源,并增强对 Bean 生命周期的控制。文章还分析了 `@Lazy` 的工作机制、使用场景、最佳实践以及常见陷阱与解决方案,帮助开发者更高效地构建可扩展、高性能的 Spring 应用程序。
128 0
Spring中最大化@Lazy注解,实现资源高效利用
|
2月前
|
Java 测试技术 编译器
@GrpcService使用注解在 Spring Boot 中开始使用 gRPC
本文介绍了如何在Spring Boot应用中集成gRPC框架,使用`@GrpcService`注解实现高效、可扩展的服务间通信。内容涵盖gRPC与Protocol Buffers的原理、环境配置、服务定义与实现、测试方法等,帮助开发者快速构建高性能的微服务系统。
533 0
下一篇
oss云网关配置