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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 事物:在一个业务流程中,通常需要多条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

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
14天前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
97 26
|
17天前
|
缓存 Java 数据库
SpringBoot缓存注解使用
Spring Boot 提供了一套方便的缓存注解,用于简化缓存管理。通过 `@Cacheable`、`@CachePut`、`@CacheEvict` 和 `@Caching` 等注解,开发者可以轻松地实现方法级别的缓存操作,从而提升应用的性能和响应速度。合理使用这些注解可以大大减少数据库的访问频率,优化系统性能。
163 89
|
2月前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
181 73
|
4天前
|
监控 Java Spring
SpringBoot:SpringBoot通过注解监测Controller接口
本文详细介绍了如何通过Spring Boot注解监测Controller接口,包括自定义注解、AOP切面的创建和使用以及具体的示例代码。通过这种方式,可以方便地在Controller方法执行前后添加日志记录、性能监控和异常处理逻辑,而无需修改方法本身的代码。这种方法不仅提高了代码的可维护性,还增强了系统的监控能力。希望本文能帮助您更好地理解和应用Spring Boot中的注解监测技术。
33 16
|
2月前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
60 21
|
1月前
|
SQL Java 关系型数据库
【SpringFramework】Spring事务
本文简述Spring中数据库及事务相关衍伸知识点。
50 9
|
2月前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
127 13
|
2月前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
2月前
|
Java Spring
【Spring配置】idea编码格式导致注解汉字无法保存
问题一:对于同一个项目,我们在使用idea的过程中,使用汉字注解完后,再打开该项目,汉字变成乱码问题二:本来a项目中,汉字注解调试好了,没有乱码了,但是创建出来的新的项目,写的注解又成乱码了。
|
9月前
|
Java API Spring
Spring容器如何使用一个注解来指定一个类型为配置类型
Spring容器如何使用一个注解来指定一个类型为配置类型
78 0