【Spring系列】- Spring事务底层原理

Spring事务底层原理

😄生命不息,写作不止
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 一个有梦有戏的人 @怒放吧德德
🌝分享学习心得,欢迎指正,大家一起学习成长!

【Spring系列】- Spring事务底层原理

前言

昨天学习了bean生命周期底层原理,今天就来接着简单学习spring事务的底层理解。

实验准备

配置文件

首先在配置文件中配置jdbcTemplate和事务管理器,并且需要开启事务的注解@EnableTransactionManagement以及@Configuration注解

@ComponentScan("com.lyd")
@EnableTransactionManagement
@Configuration
public class ApplicationConfig {
    @Bean
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(dataSource());
    }
    @Bean
    public PlatformTransactionManager transactionManager() {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());
        return transactionManager;
    }
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/eladmin?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true");
        dataSource.setUsername("root");
        dataSource.setPassword("12356");
        return dataSource;
    }
}

准备数据表

本次实验使用学生表,就简单几个字段。

【Spring系列】- Spring事务底层原理

Spring事务的底层原理

我们在需要加上事务的方法上添加@Transactional注解,然后在此方法中使用jdbcTemplate去执行SQL语句,再来执行此方法,观察可以看到,事务真的回滚了。

@Component
public class UserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Transactional
    public void test(){
        jdbcTemplate.execute("insert into student values (1, 'lyd', 18, '20183033210')");
       throw new NullPointerException();
    }
}

原理

首先spring会调用代理对象,对于事务,代理对象会通过执行事务的切面逻辑。在这个切面逻辑,Spring会去判断是否含有@Transactional事务注解,如果有才会去开启事务。spring的事务管理器会新建一个数据库连接conn,紧接着会把conn.autocommit 设置为 false ,autocommit(自动提交),每次执行完SQL后就会立马提交,因此这里需要设置为false。spring默认是开启了自动提交,当SQL执行结束之后就会提交,当遇到异常的时候,由于前面的事务都已经提升,因此就没法回滚了,所以需要把自动提交给关闭了。最后在通过第一次创建的对象(Spring个生命周期中通过构造方法创造的对象)去执行test方法。接着会去执行SQL语句,在此SQL执行完之后是不会进行提交的,在执行SQL语句之前,jdbcTemplate会去拿到事务管理器创建的这个数据库连接conn。当执行完test方法后,Spring事务会去判断是否有异常,没有异常就会提交事务(conn.commit()),否者就会事务回滚(conn.rollback());

【Spring系列】- Spring事务底层原理

Spring事务失效

接下来实现一个案例,在test方法中调用本类的另一个方法Add,两个方法都是执行了插入的SQL语句。两个方法都加上了@Transactional注解,只是在第二个方法中的注解标上一个策略:propagation = Propagation.NEVER,这个的意思是:总是非事务地执行,如果存在一个活动事务,则抛出异常。按道理来说以下代码执行将会出现异常,并且会回滚事务。

@Component
public class UserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Transactional
    public void test(){
        jdbcTemplate.execute("insert into student values (1, 'lyd', 18, '20183033210')");
        doAdd();
    }
    @Transactional(propagation = Propagation.NEVER)
    public void doAdd() {
        jdbcTemplate.execute("insert into student values (2, 'lyy', 18, '20183033211')");
    }
}

可是,最后的结果却不是预期结果。

【Spring系列】- Spring事务底层原理

失效原理

可见最后还是将两条数据插入了,显然这个事务是不回滚的,那么这是为什么呢?从上面说事务的底层原理就可以知道,当spring创建了代理对象,在代理对象内部的test方法中的切面逻辑,会去创建数据库连接等等,最后由普通对象(UserService.class通过构造方法去创建的对象)去执行test,也就是相当于是使用了普通对象去执行doAdd方法,普通对象就只是构造方法实例化的一个对象,执行doAdd并不会去检测这个@Transactional注解,因此这个事务就不会被执行到,也就不会回滚。然而spring应该是在执行代理类的test方法时候回去判断@Transactional注解,会有额外的逻辑去判断事务,也就是doAdd应该也要由代理对象去执行。

解决方案

那么有办法解决吗?办法肯定过有,接下来介绍一种解决方法

方案一

将add方法抽到另一个bean类里面

@Component
public class UserBaseService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(propagation = Propagation.NEVER)
    public void doAdd() {
        jdbcTemplate.execute("insert into student values (2, 'lyy', 18, '20183033211')");
    }
}

再来通过bean对象来执行这个doAdd方法

@Component
public class UserService {
    private JdbcTemplate jdbcTemplate;
    private UserBaseService userBaseService;
        jdbcTemplate.execute("insert into student values (1, 'lyd', 18, '20183033210')");
        userBaseService.doAdd();
    }
}

然后把数据表清空,在此执行

【Spring系列】- Spring事务底层原理

这回就报错了,而且也是我们所期望的错误,在看一下数据表,发现数据没有保存进去。

方案二

那如果我们还是想要在本类中去执行这个doAdd方法呢?其实也是可以,就是我们通过自己调用自己的方式,在本类中引用本类的bean对象,此时他就是一个代理对象,这样事务的策略也就能够实现了。

@Autowired
private UserService userService;

@Transactional
public void test(){
    jdbcTemplate.execute("insert into student values (1, 'lyd', 18, '20183033210')");
    throw new NullPointerException();
    userService.doAdd();
}

也能得到我们预期的实现效果,数据库中也没有相关数据。

【Spring系列】- Spring事务底层原理

@Configuration底层原理

在上面我们提到了jdbcTemplate获得数据库连接,那么这个又是如何得到呢?我们来看一下一开始的配置。

@Bean
public JdbcTemplate jdbcTemplate() {
    return new JdbcTemplate(dataSource());
}

@Bean
public PlatformTransactionManager transactionManager() {
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    transactionManager.setDataSource(dataSource());
    return transactionManager;
}

@Bean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/eladmin?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true");
    dataSource.setUsername("root");
    dataSource.setPassword("12356");
    return dataSource;
}

贯穿逻辑

在创建 jdbcTemplate 的bean对象的时候,会去调用 dataSource ,在创建事务管理 PlatformTransactionManager也会去调用一次 dataSource方法,在这个方法中会创建新的 dataSource,那么,所获得的事务不就不一样了吗,显然这是不行的。那么在spring中,他是如何实现单例的呢?就是通过 @Configuration 注解来实现。
其实spring会通过ThreadLocal(线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构),在spring中ThreadLocal

@Configuration原理

然而,@Configuration能够实现单例DataSource对象呢?这就是因为@Configuration也是采用了动态代理会创建ApplicationConfig的代理对象。spring会创建ApplicationConfig的代理对象,这个代理对象会去调用jdbcTemplate方法,而代理对象会执行super.jdbcTemplate(),在这个方法中需要执行dataSource()方法,他会首先去容器中找是否有dataSource的bean对象,如果有直接返回,没有就会创建,创建之后会将单例进行保存。接着transactionManager方法也是由代理对象去执行的,在他需要dataSource对象的时候,也是现去容器查找,这就能够实现他们两个的dataSource是一样的了。这样事务拿到的数据库连接就是相同了,如果是在使用dataSource这个bean对象的时候,使用的beanName是不同,那么最后得到的连接也就不同。

👍创作不易,如有错误请指正,感谢观看!记得点赞哦!👍

Original: https://www.cnblogs.com/lyd-code/p/16909632.html
Author: 怒放吧德德
Title: 【Spring系列】- Spring事务底层原理

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/798241/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • numpy 数组中的轴 axis

    numpy 数组中的轴 numpy有很多维度的数组,一维数组,二维数组,三维数组……n维数组,我们生活的是一个三维世界,因此,在这里就只讨论 一维数组,二维…

    Python 2023年8月24日
    048
  • 阿里面试题:Pandas中合并数据的5个函数,各有千秋!

    前几天,在一个群里面,看到一位朋友,说自己接到了阿里的面试,人家问了一些关于pandas的使用。其中一个问题是: pandas中合并数据的5中方法。 今天借着这个机会,就为大家盘点…

    Python 2023年8月8日
    045
  • CTFd最新动态靶场环境部署笔记(2021.08.01更新)

    前言 目前CTFd平台的搭建教程网上有很多,但也有部分写的水,不够详细,跟着那些教程部署完多多少少还是会出现不少问题,从而导致部署失败,既浪费了时间精力不说还多多少少影响了学习的进…

    Python 2023年8月11日
    0100
  • 【数据分析上手实践】读取数据

    2022/3/15 1.导入两个库 Numpy计算 Pandas 开源用于数据分析的工具 Import numpy as np Import pandas as pd import…

    Python 2023年8月6日
    052
  • Pygame(十)作业

    Pygame(十)作业 随心圆:以鼠标左键点击为圆心,画一个半径50 ,颜色随机的圆 需求分析: if event.type == pygame.MOUSEBUTTONDOWN: …

    Python 2023年9月25日
    038
  • python简介,cmd查看python版本

    一、python简介:是什么,特点是什么,有什么用 python是一门结合解释型,编译性,互动性和面向对象的脚本语言,具有很强的可读性,相比其他例如Java语言,C语言更加容易入门…

    Python 2023年5月23日
    081
  • 如何在“浏览器”里实现一个云端EDA

    本文介绍了一种在浏览器里编辑代码、仿真、看log、看波形的方法。 django介绍 django是一个由python实现的web后端框架。这里”后端”就是指…

    Python 2023年8月6日
    051
  • Python爬虫之Web自动化测试工具Selenium&&Chrome handless

    ​​ @作者 : SYFStrive @博客首页 : HomePage; 🥧 上一篇续文传送门 📌: 个人社区(欢迎大佬们加入) 👉:社区链接🔗 📌: 如果觉得文章对你有帮助可以点…

    Python 2023年8月2日
    053
  • 从0搭建vue3组件库:Shake抖动组件

    先看下效果 其实就是个抖动效果组件,实现起来也非常简单。之所以做这样一个组件是为了后面写Form表单的时候会用到它做一个规则校验,比如下面一个简单的登录页面,当点击登录会提示用户哪…

    Python 2023年10月18日
    052
  • 亚马逊首次亮相中性原子量子计算机Aquila

    Aquila处理器内饰(图片来源:网络) 亚马逊网络 服务(AWS)将在其名为Amazon Braket的特殊云服务器中托管量子计算机Aquila。这是量子计算第一次可以直接 从A…

    Python 2023年10月24日
    038
  • pyinstaller和venv的关系

    网上蛮多提到pyinstaller的情况,在执行 pyinstaller -F a.py的时候会提示pyinstaller不是内部也不是外部命令,一般如果不单独弄venv,修改环境…

    Python 2023年10月31日
    042
  • flask+vue全栈部署方式

    新公司项目技术栈用的falsk+vue,在这里记录一下部署方式,以备以后回顾。 我这边的是用systemctl+nginx+gunicorn+virtualenv的架构进行部署的。…

    Python 2023年8月9日
    047
  • Python基于深度学习算法实现图书推荐系统项目实战

    说明:这是一个机器学习实战项目(附带 数据+代码+文档+视频讲解),如需 数据+代码+文档+视频讲解可以直接到文章最后获取。 1.项目背景 在线推荐系统是许多电子商务网站的事情。推…

    Python 2023年9月26日
    039
  • python 爬虫scrapy框架的基本使用

    scrapy 创建项目步骤: 1.安装scrapy pip install scrapy 打开cmd 随便进入一个文件夹…. 1.运行cmd命令创建(前提是安装了scr…

    Python 2023年10月3日
    033
  • 爬虫之Scrapy框架

    安装 pip install scrapy在命令行输入scrapy,出现提示说明安装成功 ; 创建项目 scrapy startproject my_scrapy会生成一个项目名文…

    Python 2023年10月2日
    037
  • scrapy的各个模块的作用以及数据在从各个模块的流向

    scrapy的各个模块的作用以及数据在从各个模块的流向 ​ 引擎,处理整个系统的数据流处理、触发事务,是整个框架的核心 ​ 项目、它定义了爬取的结果的数据结构,爬取的数据会被赋值成…

    Python 2023年10月3日
    058
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球