Spring @Transactional工作原理

本文将深入研究Spring的事务管理。主要介绍@Transactional在底层是如何工作的。之后的文章将介绍:

  • propagation(事务传播)和isolation(隔离性)等属性的使用
  • 事务使用的陷阱有哪些以及如何避免

JPA和事务管理

很重要的一点是JPA本身并不提供任何类型的声明式事务管理。如果在依赖注入容器之外使用JPA,事务处理必须由开发人员编程实现。


1

2

3

4

5

6

7

8

9

10

11

12

UserTransaction utx = entityManager.getTransaction();

    try {

        utx.begin();

        businessLogic();

        utx.commit();

    } catch(Exception ex) {

        utx.rollback();

        throw ex;

    }

这种方式的事务管理使事务范围可以在代码中很清晰地表达出来,但它有以下缺点:

  • 容易出现重复代码和错误
  • 任何错误可能产生较大的影响
  • 错误难以调试和复现
  • 降低了代码库的可读性
  • 如果该方法调用了其他的事务方法如何处理呢?

使用Spring @Transactional

使用Spring @Transactional,上面的代码就简化为:


1

2

3

4

@Transactional

    public void businessLogic() {

        ... use entity manager inside a transaction ...

    }

代码更加简洁,可读性更好,也是目前Spring中事务处理的推荐方式。

通过使用@Transactional,事务传播等很多重要方面可以自动处理。这种情况下如果businessLogic()调用了其他事务方法,该方法将根据选项确定如何加入正在运行事务。

这个强大机制的一个潜在缺点是它隐藏了底层的运行,当它不能正常工作时很难调试。

@Transactional含义

关于@Transactional,关键点之一是要考虑两个独立的概念,它们都有各自的范围和生命周期:

  • persistence context(持久化上下文)
  • database transaction(事务)

@Transactional本身定义了单个事务的范围。这个事务在persistence context的范围内。

JPA中的持久化上下文是EntityManager,内部实现使用了Hibernate Session(使用Hibernate作为持久化provider)。

持久化上下文仅仅是一个同步对象,它记录了有限集合的Java对象的状态,并且保证这些对象的变化最终持久化到数据库。

这是与单个事务非常不同的概念。一个Entity Manager可以跨越多个事务使用,而且的确是这样使用的。

EntityManager何时跨越多个事务?

最常见的情况是应用使用Open Session In View模式处理懒初始化异常时,之前的文章介绍过这种做法的优势和劣势

这种情况下视图层运行的多个查询处于独立的事务中,而不是单事务的业务逻辑,但这些查询由相同的entity manager管理。

另一种情况是开发人员将持久化上下文标记为PersistenceContextType.EXTENDED,这表示它能够响应多个请求。

如何定义EntityManager和Transaction之间的关系?

这由应用开发者来选择,但是JPA Entity Manager最常用的方式是“Entity Manager per application transaction”(每个事务都有自己的实体管理器)模式。entity manager注入的常用方法是:


1

2

@PersistenceContext

    private EntityManager em;

这里默认为“Entity Manager per transaction”模式。这种模式下如果在@Transactional方法内部使用该Entity Manager,那么该方法将在单一事务中运行。

@PersistenceContext如何工作?

随之而来的问题就是@PersistenceContext如何仅在容器启动时注入entity manager,假定entity manager生命周期很短暂,而且每次请求需要多个entity manager。

答案是它不能:EntityManager是一个接口,注入到spring bean中的不是entity manager本身,而是在运行时代理具体entity manager的context aware proxy(上下文感知代理)

通常用于代理的具体类为SharedEntityManagerInvocationHandler,借助调试器可以确认这一点。

那么@Transactional如何工作?

实现了EntityManager接口的持久化上下文代理并不是声明式事务管理的唯一部分,事实上包含三个组成部分:

  • EntityManager Proxy本身
  • 事务的切面
  • 事务管理器

看一下这三部分以及它们之间的相互作用。

事务的切面

事务的切面是一个“around(环绕)”切面,在注解的业务方法前后都可以被调用。实现切面的具体类是TransactionInterceptor

事务的切面有两个主要职责:

  • 在’before’时,切面提供一个调用点,来决定被调用业务方法应该在正在进行事务的范围内运行,还是开始一个新的独立事务。
  • 在’after’时,切面需要确定事务被提交,回滚或者继续运行。

在’before’时,事务切面自身不包含任何决策逻辑,是否开始新事务的决策委派给事务管理器完成。

事务管理器

事务管理器需要解决下面两个问题:

  • 新的Entity Manager是否应该被创建?
  • 是否应该开始新的事务?

这些需要事务切面’before’逻辑被调用时决定。事务管理器的决策基于以下两点:

  • 事务是否正在进行
  • 事务方法的propagation属性(比如REQUIRES_NEW总要开始新事务)

如果事务管理器确定要创建新事务,那么将:

  • 创建一个新的entity manager
  • entity manager绑定到当前线程
  • 从数据库连接池中获取连接
  • 将连接绑定到当前线程

使用ThreadLocal变量将entity manager和数据库连接都绑定到当前线程。

事务运行时他们存储在线程中,当它们不再被使用时,事务管理器决定是否将他们清除。

程序的任何部分如果需要当前的entity manager和数据库连接都可以从线程中获取。

EntityManager proxy

EntityManager proxy(前面已经介绍过)就是谜题的最后一部分。当业务方法调用entityManager.persist()时,这不是由entity manager直接调用的。

而是业务方法调用代理,代理从线程获取当前的entity manager,前面介绍过事务管理器将entity manager绑定到线程。

了解了@Transactional机制的各个部分,我们来看一下实现它的常用Spring配置。

整合三个部分

如何将三个部分组合起来使事务注解可以正确地发挥作用呢?首先定义entity manager工厂。

这样就可以通过持久化上下文注解注入Entity Manager proxy。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

@Configuration

    public class EntityManagerFactoriesConfiguration {

        @Autowired

        private DataSource dataSource;

        @Bean(name = "entityManagerFactory")

        public LocalContainerEntityManagerFactoryBean emf() {

            LocalContainerEntityManagerFactoryBean emf = ...

            emf.setDataSource(dataSource);

            emf.setPackagesToScan(

                new String[] {"your.package"});

            emf.setJpaVendorAdapter(

                new HibernateJpaVendorAdapter());

            return emf;

        }

    }

下一步实现配置事务管理器和在@Transactional注解的类中应用事务的切面。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

@Configuration

    @EnableTransactionManagement

    public class TransactionManagersConfig {

        @Autowired

        EntityManagerFactory emf;

        @Autowired

        private DataSource dataSource;

        @Bean(name = "transactionManager")

        public PlatformTransactionManager transactionManager() {

            JpaTransactionManager tm =

                new JpaTransactionManager();

                tm.setEntityManagerFactory(emf);

                tm.setDataSource(dataSource);

            return tm;

        }

    }

注解@EnableTransactionManagement通知Spring,@Transactional注解的类被事务的切面包围。这样@Transactional就可以使用了。

总结

Spring声明式事务管理机制非常强大,但它可能被误用或者容易发生配置错误。

当这个机制不能正常工作或者未达到预期运行结果等问题出现时,理解它的内部工作情况是很有帮助的。

需要记住的最重要的一点是,要考虑到两个概念:事务和持久化上下文,每个都有自己不可读的明显的生命周期。

时间: 2024-12-26 15:51:43

Spring @Transactional工作原理的相关文章

关于Spring框架的 @Transactional工作原理介绍

最近做的项目有特别留意到spring的  @Transactional,于是,在网上查找一番. 本文将深入研究Spring的事务管理.主要介绍@Transactional在底层是如何工作的.之后的文章将介绍: propagation(事务传播)和isolation(隔离性)等属性的使用 事务使用的陷阱有哪些以及如何避免 JPA和事务管理 很重要的一点是JPA本身并不提供任何类型的声明式事务管理.如果在依赖注入容器之外使用JPA,事务处理必须由开发人员编程实现. 1 2 3 4 5 6 7 8 9

Spring MVC工作原理

Spring MVC工作流程图 图一 图二  Spring工作流程描述 1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获: 2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI).然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回: 3.

spring mvc 工作原理

SpringMVC框架介绍 1) Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还是 Struts 这样的 Web 框架.通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术.Velocity.Til

关于spring框架工作原理的初解

一:spring基本概念 1)struts2是web框架,hibernate是orm框架 2)spring是容器框架,创建bean,维护bean之间的关系 3)spring可以管理web层,持久层,业务层,dao层,spring可以配置各个层的组件,并且维护各个层的关系 二:spring核心原理 1.IOC控制反转 概念:控制权由对象本身转向容器,由容器根据配置文件创建对象实例并实现各个对象的依赖关系. 核心:bean工厂 IoC(Inverse of Control)的字面意思是控制反转,它包

Spring的工作原理核心组件和应用

Spring框架 Spring 是管理多个java类的容器框架,注意是类不管理接口. Spring 的主要功能 Ioc 反转控制和 DI 依赖注入. 注入的方式可以是构造函数赋值也可以是 set方法赋值推荐用set方法赋值 在Spring一加载的阶段就实例化.和初始化(注入值的话)在Spring配置文件中的多个java类.等待用户的调用,用服务器端的缓存消耗换取客户端的快速响应. Ioc:反转控制.当实例化一个bean类时,传统的操作方式是由调用者进行实例化.在spring中,不再由调用者进行实

Spring的工作原理

一.什么是Spring (1).Spring真正的精华是它的Ioc模式实现的BeanFactory和AOP,它自己在这个基础上延伸的功能有些画蛇添足. (2). Spring它是一个开源的项目,而且目前非常活跃:它基于IoC(Inversion of Control,反向控制)和AOP的构架多层j2ee系统的框架,但它不强迫你必须在每一层 中必须使用Spring,因为它模块化的很好,允许你根据自己的需要选择使用它的某一个模块:它实现了很优雅的MVC,对不同的数据访问技术提供了统一的 接口,采用I

Spring学习之旅(四)Spring工作原理再探

上篇博文对Spring的工作原理做了个大概的介绍,想看的同学请出门左转.今天详细说几点. (一)Spring IoC容器及其实例化与使用 Spring IoC容器负责Bean的实例化.配置和组装工作有两个接口:BeanFactory和ApplicationContext.其中ApplicationContext继承于BeanFactory,对企业级应用开发提供了更多的支持.在实际应用中都是用该接口. 1)实例化Spring容器(主要有四种) 1.ClassPathXmlApplicationCo

利用反射模拟一个spring的内部工作原理

这个简单的案例是实行了登录和注册的功能,没有链接数据库. 在bean中id 是唯一的,id和name的区别在于id不能用特殊字符而name可以用特殊字符,比如:/-\.... 1 package com.obtk.reflect; 2 3 public class Logon { 4 /** 5 * 帐号密码长度大于六位字符就成功,否则失败! 6 * */ 7 public String select(String name, String pass) { 8 if (name.length()

Spring aop 原始的工作原理的理解

理解完aop的名词解释,继续学习spring aop的工作原理. 首先明确aop到底是什么东西?又如何不违单一原则并实现交叉处理呢? 如果对它的认识只停留在面向切面编程,那就脏了.从oop(Object Oriented Programming)说起,oop引入封装,多态,继承等概念建立对象层次的结构,处理公共行为属性的集合.对于一个系统而言,需要把分散对象整合到一起的时候,oop就虚了,因为这样的需求已经在对象层次之上了.如订单模块,还款模块都需要User对象配合(当然不止于User对象完成的