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

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

JPA和事务管理

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

UserTransaction utx = entityManager.getTransaction();
try{utx.begin();businessLogic();utx.commit();
} catch(Exception ex){utx.rollback();throw ex;
}

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

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

使用Spring @Transactional

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

@Transactional
public void businessLogic(){...your code
}

代码更加简洁,可读性更好,也是目前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注入的常用方法是:

@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。

@Configuration
public class EntityManagerFactoriesConfiguration{@Autowiredprivate 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注解的类中应用事务的切面。

@Configuration
@EnableTransactionManagement
public class TransactionManagersConfig{@AutowiredEntityManagerFactory emf;@Autowiredprivate DataSource dataSource;@Bean(name="transactionManager")public PlatformTransactionManager transactionManager(){JpaTransactionManager tm=new JpaTransactionManager();tm.setEntityManagerFactory(emf);tm.setDataSource(dataSource);return emf;}
}

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

总结

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

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

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

转载于:https://www.cnblogs.com/luchangjiang/p/10488150.html

Java:Spring @Transactional工作原理相关推荐

  1. 事务之五:Spring @Transactional工作原理

    本文将深入研究Spring的事务管理.主要介绍@Transactional在底层是如何工作的. JPA(Java Persistence API--java持久层)和事务管理 很重要的一点是JPA本身 ...

  2. transactional注解的使用_Java:Spring @Transactional工作原理

    本文将深入研究Spring的事务管理.主要介绍@Transactional在底层是如何工作的.之后的文章将介绍: propagation(事务传播)和isolation(隔离性)等属性的使用 事务使用 ...

  3. Spring的工作原理(一)简介

    Spring的工作原理 有时候面试的时候,面试官:会用Spring么?答:会,我们公司就用的Spring.面试官:Spring怎么进行控制反转的?切面怎么实现的?切面回用于哪一些场景?用到了哪一些设计 ...

  4. spring的工作原理介绍

    作为一名Java Coder,无时无刻都在用Spring这个框架,可我们对他的了解有多少呢.下面我自己整理了一些思路,有问题还请大佬多多指教. Spring的工作原理就是让一个对象的创建不用new就可 ...

  5. java gc的工作原理、如何优化GC的性能、如何和GC进行有效的交互

    java gc的工作原理.如何优化GC的性能.如何和GC进行有效的交互 一个优秀的Java 程序员必须了解GC 的工作原理.如何优化GC的性能.如何和GC进行有效的交互,因为有一些应用程序对性能要求较 ...

  6. Spring MVC工作原理

    转载自  Spring MVC工作原理 Spring MVC框架介绍 Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring M ...

  7. Java HashMap的工作原理 及各种Map区别

    2019独角兽企业重金招聘Python工程师标准>>> 一.Java HashMap的工作原理 jdk1.7下HashMap数据结构:数组加链表,链表长度没有8的限制: jdk1.8 ...

  8. Java执行引擎工作原理:方法调用

    Java执行引擎工作原理:方法调用 方法调用如何实现 函数指针和指针函数 CallStub源码详解 Git链接(有HotSpot源码) 1 方法调用如何实现 计算机核心三大功能:方法调用.取指.运算 ...

  9. 春天到了,讲讲Spring的工作原理

    一.春天到了,讲讲Spring的工作原理 在致力于优质IT知识出版分享的异步社区,有这么一本书--两版累计销售了近10w本,它可是完完全全靠着自己过硬的内容实力打出的这片天! 第二版已出版4年,基于S ...

  10. Java 程序的工作原理

    文章目录 Java 语言的主要特点 Java 体系 从源码到机器码的过程 JDK.JRE 与 JVM 是什么 字节码解释过程 Java两大核心机制之JVM Java两大核心机制之GC Java 语言的 ...

最新文章

  1. 你所知道的Java单例模式并不是单例模式
  2. 创业第一站丨产品经理、海归转型成创业者有多难?
  3. oracle表复制为mysql表_oracle 将数据库的表复制到另一个数据库表内
  4. TensorFlow10-多层神经网络建模,存储和载入
  5. mysql 如何按时间备份_如何定时备份mysql数据库
  6. 【leetcode】1053. Previous Permutation With One Swap
  7. 拓端tecdat|游记数据感知旅游目的地形象
  8. Redhat linux 5 Server相关介绍
  9. 手机qq的位置服务器,腾讯面试题:腾讯服务器每秒有2w个QQ号同时上线,找出5min内重新登入的qq号并打印出来。...
  10. Centos虚拟机桥接模式无法连接外网的解决
  11. 卡方检验,U检验,t检验,F检验
  12. 第九周上机项目3:个人所得税计算器
  13. 数据分析的重要性体现在哪里?
  14. 【菠萝狗四足机器人】二次开发教程--第一章 【简介与开发环境搭建】
  15. wget通过代理下载之错误解决1(Proxy tunneling failed: Forwarding failureUnable to establish SSL connection.)
  16. 《编程之美》笔记之——24点游戏
  17. String.valueOf()和Integer.valueOf()方法的使用
  18. 埋点设计思路 - 基础知识和设计流程
  19. skynet环境搭建
  20. Google、华为、今日头条都在用的绩效管理OKR是什么? | 推荐收藏

热门文章

  1. android stuido 快捷键
  2. 【转】Java 中正确使用 hashCode 和 equals 方法
  3. OLE 操作Excel 祥解
  4. [ER/Studio]进行不同版本数据库结构的合并
  5. 【收藏】一份最新的、全面的NLP文本分类综述
  6. 机器学习面试-数学基础
  7. 每日算法系列【LeetCode 556】下一个更大元素 III
  8. leetcode—10.栈题型python解答
  9. 百面机器学习—5.SVM要点总结
  10. 《MYSQL必知必会》—1.了解SQL