一文带你认识Spring事务

栏目: Java · 发布时间: 5年前

内容简介:只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:Spring事务管理我相信大家都用得很多,但可能仅仅局限于一个

前言

只有光头才能变强。

文本已收录至我的GitHub仓库,欢迎Star: https://github.com/ZhongFuCheng3y/3y

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的生命周期)也是一个 常考 的知识点,我在秋招也 重新 整理了一下步骤,因为比较重要,所以还是在这里贴一下吧:

配置/实现
配置/实现了
init-method

一文带你认识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事务管理一些比较重要的知识点,当然在学习的过程中还看到其他的知识点,如果想要继续学习的同学不妨通过下面给出的参考资料继续阅读。

参考资料:

乐于输出 干货Java 技术公众号:Java3y。公众号内有200多篇 原创 技术文章、海量视频资源、精美脑图,不妨来 关注 一下!

一文带你认识Spring事务

觉得我的文章写得不错,不妨点一下


以上所述就是小编给大家介绍的《一文带你认识Spring事务》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

豆瓣,流行的秘密

豆瓣,流行的秘密

黄修源 / 机械工业出版社 / 2009-9 / 29.00

380万人为何会齐聚豆瓣? HIN1和SARS是如何传播扩散开的? 贾君鹏何以快速窜红网络? 通过创新扩散的理论的分析和说明,给出了所有这些问题的答案! 这本书从豆瓣的流行现象说开来,应用了创新扩散等传播学道理来解释了豆瓣如何流行起来,同时作者还同时用创新扩散的理论解释了为何会出现世界变平的现象,长尾理论,SARS病毒的高速传播等。 作者以前任豆瓣设计师的身份以自己亲......一起来看看 《豆瓣,流行的秘密》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具