我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Spring事务的详细介绍

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Spring事务的详细介绍

本篇内容介绍了“Spring事务的详细介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

前言

Spring事务管理我相信大家都用得很多,但可能仅仅局限于一个@Transactional注解或者在XML中配置事务相关的东西。不管怎么说,日常可能足够我们去用了。但作为程序员,无论是为了面试还是说更好把控自己写的代码,还是应该得多多了解一下Spring事务的一些细节。

这里我抛出几个问题,看大家能不能瞬间答得上:

  • 如果嵌套调用含有事务的方法,在Spring事务管理中,这属于哪个知识点?

  • 我们使用的框架可能是Hibernate/JPA或者是Mybatis,都知道的底层是需要一个session/connection对象来帮我们执行操作的。要保证事务的完整性,我们需要多组数据库操作要使用同一个session/connection对象,而我们又知道Spring IOC所管理的对象默认都是单例的,这为啥我们在使用的时候不会引发线程安全问题呢?内部Spring到底干了什么?

  • 人家所说的BPP又是啥东西?

  • Spring事务管理重要接口有哪几个?

一、阅读本文需要的基础知识

阅读这篇文章的同学我默认大家都对Spring事务相关知识有一定的了解了。(ps:如果不了解点解具体的文章去阅读再回到这里来哦)

我们都知道,Spring事务是Spring AOP的最佳实践之一,所以说AOP入门基础知识(简单配置,使用)是需要先知道的。如果想更加全面了解AOP可以看这篇文章:AOP重要知识点(术语介绍、全面使用)。说到AOP就不能不说AOP底层原理:动态代理设计模式。到这里,对AOP已经有一个基础的认识了。于是我们就可以使用XML/注解方式来配置Spring事务管理。

在IOC学习中,可以知道的是Spring中Bean的生命周期(引出BPP对象)并且IOC所管理的对象默认都是单例的:单例设计模式,单例对象如果有"状态"(有成员变量),那么多线程访问这个单例对象,可能就造成线程不安全。那么何为线程安全?,解决线程安全有很多方式,但其中有一种:让每一个线程都拥有自己的一个变量:ThreadLocal

如果对我以上说的知识点不太了解的话,建议点击蓝字进去学习一番。

二、两个不靠谱直觉的例子

2.1第一个例子

之前朋友问了我一个例子:

在Service层抛出Exception,在Controller层捕获,那如果在Service中有异常,那会事务回滚吗?

// Service方法

@Transactional
public Employee addEmployee() throws Exception {

    Employee employee = new Employee("3y", 23);
    employeeRepository.save(employee);
    // 假设这里出了Exception
    int i = 1 / 0;

    return employee;
}

// Controller调用
@RequestMapping("/add")
public Employee addEmployee() {
    Employee employee = null;
    try {
        employee = employeeService.addEmployee();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return employee;

}

第一反应:不会回滚吧。

  • 我当时是这样想的:因为Service层已经抛出了异常,由Controller捕获。那是否回滚应该由Controller的catch代码块中逻辑来决定,如果catch代码块没有回滚,那应该是不会回滚。

但朋友经过测试说,可以回滚阿。(pappapa打脸)

Spring事务的详细介绍

看了一下文档,原来文档有说明:

By default checked exceptions do not result in the transactional interceptor marking the transaction for rollback and instances of RuntimeException and its  subclasses do

结论:如果是编译时异常不会自动回滚,如果是运行时异常,那会自动回滚

2.2第二个例子

第二个例子来源于知乎@柳树文章,文末会给出相应的URL

我们都知道,带有@Transactional注解所包围的方法就能被Spring事务管理起来,那如果我在当前类下使用一个没有事务的方法去调用一个有事务的方法,那我们这次调用会怎么样?是否会有事务呢?

用代码来描述一下:

// 没有事务的方法去调用有事务的方法
public Employee addEmployee2Controller() throws Exception {

    return this.addEmployee();
}

@Transactional
public Employee addEmployee() throws Exception {

    employeeRepository.deleteAll();
    Employee employee = new Employee("3y", 23);

    // 模拟异常
    int i = 1 / 0;

    return employee;
}

我第一直觉是:这跟Spring事务的传播机制有关吧。

其实这跟Spring事务的传播机制没有关系,下面我讲述一下:

  • Spring事务管理用的是AOP,AOP底层用的是动态代理。所以如果我们在类或者方法上标注注解@Transactional,那么会生成一个代理对象

接下来我用图来说明一下:

Spring事务的详细介绍

显然地,我们拿到的是代理(Proxy)对象,调用addEmployee2Controller()方法,而addEmployee2Controller()方法的逻辑是target.addEmployee(),调用回原始对象(target)的addEmployee()。所以这次的调用压根就没有事务存在,更谈不上说Spring事务传播机制了。

原有的数据:

Spring事务的详细介绍

测试结果:压根就没有事务的存在

Spring事务的详细介绍
2.2.1再延伸一下

从上面的测试我们可以发现:如果是在本类中没有事务的方法来调用标注注解@Transactional方法,最后的结论是没有事务的。那如果我将这个标注注解的方法移到别的Service对象上,有没有事务?

@Service
public class TestService {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Transactional
    public Employee addEmployee() throws Exception {

        employeeRepository.deleteAll();

        Employee employee = new Employee("3y", 23);

        // 模拟异常
        int i = 1 / 0;

        return employee;
    }

}


@Service
public class EmployeeService {

    @Autowired
    private TestService testService;
    // 没有事务的方法去调用别的类有事务的方法
    public Employee addEmployee2Controller() throws Exception {
        return testService.addEmployee();
    }
}

测试结果:

Spring事务的详细介绍

因为我们用的是代理对象(Proxy)去调用addEmployee()方法,那就当然有事务了。

看完这两个例子,有没有觉得3y的直觉是真的水

三、Spring事务传播机制

如果嵌套调用含有事务的方法,在Spring事务管理中,这属于哪个知识点?

在当前含有事务方法内部调用其他的方法(无论该方法是否含有事务),这就属于Spring事务传播机制的知识点范畴了。

Spring事务基于Spring AOP,Spring AOP底层用的动态代理,动态代理有两种方式:

  • 基于接口代理(JDK代理)

    • 基于接口代理,凡是类的方法非public修饰,或者用了static关键字修饰,那这些方法都不能被Spring AOP增强

  • 基于CGLib代理(子类代理)

    • 基于子类代理,凡是类的方法使用了private、static、final修饰,那这些方法都不能被Spring AOP增强

至于为啥以上的情况不能增强,用你们的脑瓜子想一下就知道了。

值得说明的是:那些不能被Spring AOP增强的方法并不是不能在事务环境下工作了。只要它们被外层的事务方法调用了,由于Spring事务管理的传播级别,内部方法也可以工作在外部方法所启动的事务上下文中

至于Spring事务传播机制的几个级别,我在这里就不贴出来了。这里只是再次解释“啥情况才是属于Spring事务传播机制的范畴”。

四、多线程问题

我们使用的框架可能是Hibernate/JPA或者是Mybatis,都知道的底层是需要一个session/connection对象来帮我们执行操作的。要保证事务的完整性,我们需要多组数据库操作要使用同一个session/connection对象,而我们又知道Spring IOC所管理的对象默认都是单例的,这为啥我们在使用的时候不会引发线程安全问题呢?内部Spring到底干了什么?

回想一下当年我们学Mybaits的时候,是怎么编写Session工具类?

Spring事务的详细介绍

没错,用的就是ThreadLocal,同样地,Spring也是用的ThreadLocal。

以下内容来源《精通 Spring4.x》

我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态的“状态性对象”采用ThreadLocal封装,让它们也成为线程安全的“状态性对象”,因此,有状态的Bean就能够以singleton的方式在多线程中工作。

我们可以试着点一下进去TransactionSynchronizationManager中看一下:

Spring事务的详细介绍

五、啥是BPP?

BBP的全称叫做:BeanPostProcessor,一般我们俗称对象后处理器

  • 简单来说,通过BeanPostProcessor可以对我们的对象进行“加工处理”。

Spring管理Bean(或者说Bean的生命周期)也是一个常考的知识点,我在秋招也重新整理了一下步骤,因为比较重要,所以还是在这里贴一下吧:

  1. ResouceLoader加载配置信息

  2. BeanDefintionReader解析配置信息,生成一个一个的BeanDefintion

  3. BeanDefintion由BeanDefintionRegistry管理起来

  4. BeanFactoryPostProcessor对配置信息进行加工(也就是处理配置的信息,一般通过PropertyPlaceholderConfigurer来实现)

  5. 实例化Bean

  6. 如果该Bean配置/实现了InstantiationAwareBean,则调用对应的方法

  7. 使用BeanWarpper来完成对象之间的属性配置(依赖)

  8. 如果该Bean配置/实现了Aware接口,则调用对应的方法

  9. 如果该Bean配置了BeanPostProcessor的before方法,则调用

  10. 如果该Bean配置了init-method或者实现InstantiationBean,则调用对应的方法

  11. 如果该Bean配置了BeanPostProcessor的after方法,则调用

  12. 将对象放入到HashMap中

  13. 最后如果配置了destroy或者DisposableBean的方法,则执行销毁操作

Spring事务的详细介绍

其中也有关于BPP图片:

Spring事务的详细介绍

5.1为什么特意讲BPP?

Spring AOP编程底层通过的是动态代理技术,在调用的时候肯定用的是代理对象。那么Spring是怎么做的呢?

我只需要写一个BPP,在postProcessBeforeInitialization或者postProcessAfterInitialization方法中,对对象进行判断,看他需不需要织入切面逻辑,如果需要,那我就根据这个对象,生成一个代理对象,然后返回这个代理对象,那么最终注入容器的,自然就是代理对象了。

Spring提供了BeanPostProcessor,就是让我们可以对有需要的对象进行“加工处理”啊!

六、认识Spring事务几个重要的接口

Spring事务可以分为两种:

  • 编程式事务(通过代码的方式来实现事务)

  • 声明式事务(通过配置的方式来实现事务)

编程式事务在Spring实现相对简单一些,而声明式事务因为封装了大量的东西(一般我们使用简单,里头都非常复杂),所以声明式事务实现要难得多。

在编程式事务中有以下几个重要的了接口:

  • TransactionDefinition:定义了Spring兼容的事务属性(比如事务隔离级别、事务传播、事务超时、是否只读状态)

  • TransactionStatus:代表了事务的具体运行状态(获取事务运行状态的信息,也可以通过该接口间接回滚事务等操作)

  • PlatformTransactionManager:事务管理器接口(定义了一组行为,具体实现交由不同的持久化框架来完成---类比JDBC)

Spring事务的详细介绍

在声明式事务中,除了TransactionStatus和PlatformTransactionManager接口,还有几个重要的接口:

  • TransactionProxyFactoryBean:生成代理对象

  • TransactionInterceptor:实现对象的拦截

  • TransactionAttrubute:事务配置的数据

“Spring事务的详细介绍”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Spring事务的详细介绍

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Spring事务的详细介绍

本篇内容介绍了“Spring事务的详细介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言Spring事务管理我相信大家都用得很多,但可能
2023-06-04

详细介绍Spring的配置文件

这篇文章主要为大家详细介绍了Spring中的配置文件的命名以及它的配置文件都有些什么。文中的示例代码讲解详细,感兴趣的小伙伴可以跟上小编一起学习一下
2022-11-13

Spring后处理器详细介绍

Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理。可以在​Spring容器通过插入一个或多个BeanPostProcessor的实现来完成实例化,配置和初始化一个​bean​之后实现一些自定义逻辑回调方法<BR>
2023-02-07

Spring MVC 与 CORS跨域的详细介绍

1. CORS 简介同源策略(same origin policy)是浏览器安全的基石。在同源策略的限制下,非同源的网站之间不能发送 ajax 请求的。为了解决这个问题,w3c 提出了跨源资源共享,即 CORS(Cross-Origin R
2023-05-31

Spring的Ioc模拟实现详细介绍

简单来说就是当自己需要一个对象的时候不需要自己手动去new一个,而是由其他容器来帮你提供;Spring里面就是IOC容器。例如:在Spring里面经常需要在Service这个装配一个Dao,一般是使用@Autowired注解:类似如下pub
2023-05-30

Spring Bean后处理器详细介绍

Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理。可以在​Spring容器通过插入一个或多个BeanPostProcessor的实现来完成实例化,配置和初始化一个​bean​之后实现一些自定义逻辑回调方法
2023-01-28

Spring事务传播中嵌套调用实现方法详细介绍

Spring事务的本质就是对数据库事务的支持,没有数据库事务,Spring是无法提供事务功能的。Spring只提供统一的事务管理接口,具体实现都是由数据库自己实现的,Spring会在事务开始时,根据当前设置的隔离级别,调整数据库的隔离级别,由此保持一致
2022-11-13

Redis 事务与过期时间详细介绍

Redis 事务与过期时间详细介绍 一、Redis事务:Redis中支持事务,事务即为当我们需要执行几条命令时,要么这几条命令都不执行,要么都执行: 1、开始事务写入:multi2、然后写入命令,注意写完事务要执行的每条命令之后回车即可,命
2022-06-04

Nginx服务详细介绍

Nginx是lgor Sysoev为俄罗斯访问量第二的rambler.ru站点设计开发的。从2004年发布至今,凭借开源的力量,已经接近成熟与完善。Nginx功能丰富,可作为HTTP服务器,也可作为反向代理服务器,邮件服务器。支持FastC
2023-06-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录