事务之五:Spring @Transactional工作原理
本文将深入研究Spring的事务管理。主要介绍@Transactional
在底层是如何工作的。
JPA(Java Persistence API--java持久层)和事务管理
很重要的一点是JPA本身并不提供任何类型的声明式事务管理。如果在依赖注入容器之外使用JPA,事务处理必须由开发人员编程实现。
UserTransaction utx = entityManager.getTransaction(); try {utx.begin();businessLogic();utx.commit();} catch(Exception ex) {utx.rollback();throw ex;}
这种方式的事务管理使事务范围可以在代码中很清晰地表达出来,但它有以下缺点:
- 容易出现重复代码和错误
- 任何错误可能产生较大的影响
- 错误难以调试和复现
- 降低了代码库的可读性
- 如果该方法调用了其他的事务方法如何处理呢?
使用Spring @Transactional
使用Spring @Transactional
,上面的代码就简化为:
@Transactionalpublic 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注入的常用方法是:
@PersistenceContextprivate 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。
@Configurationpublic 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@EnableTransactionManagementpublic class TransactionManagersConfig {@AutowiredEntityManagerFactory emf;@Autowiredprivate 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声明式事务管理机制非常强大,但它可能被误用或者容易发生配置错误。
当这个机制不能正常工作或者未达到预期运行结果等问题出现时,理解它的内部工作情况是很有帮助的。
需要记住的最重要的一点是,要考虑到两个概念:事务和持久化上下文,每个都有自己不可读的明显的生命周期。
事务之五:Spring @Transactional工作原理相关推荐
- transactional注解的使用_Java:Spring @Transactional工作原理
本文将深入研究Spring的事务管理.主要介绍@Transactional在底层是如何工作的.之后的文章将介绍: propagation(事务传播)和isolation(隔离性)等属性的使用 事务使用 ...
- 春天到了,讲讲Spring的工作原理
一.春天到了,讲讲Spring的工作原理 在致力于优质IT知识出版分享的异步社区,有这么一本书--两版累计销售了近10w本,它可是完完全全靠着自己过硬的内容实力打出的这片天! 第二版已出版4年,基于S ...
- Spring的工作原理(一)简介
Spring的工作原理 有时候面试的时候,面试官:会用Spring么?答:会,我们公司就用的Spring.面试官:Spring怎么进行控制反转的?切面怎么实现的?切面回用于哪一些场景?用到了哪一些设计 ...
- Spring MVC工作原理
转载自 Spring MVC工作原理 Spring MVC框架介绍 Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring M ...
- spring的工作原理介绍
作为一名Java Coder,无时无刻都在用Spring这个框架,可我们对他的了解有多少呢.下面我自己整理了一些思路,有问题还请大佬多多指教. Spring的工作原理就是让一个对象的创建不用new就可 ...
- Spring Mvc工作原理图解
Spring Mvc工作原理图解 先来一张图: 目前还是有些疑惑,因为是初学 思考了大半天,整理了初步的一些工作原理: 如图上所述: 1.用户(打开网站,输入网址url)发送请求. 2.用户的请求会通 ...
- Struts1、Struts2、Hibernate、Spring框架工作原理介绍
Struts1工作原理 Struts1工作原理图 1 .初始化: struts 框架的总控制器 ActionServlet 是一个 Servlet ,它在 web.xml 中配置成自动启动的 Serv ...
- spring的工作原理
一. IoC(Inversion of control): 控制反转 1.IoC: 概念:控制权由对象本身转向容器:由容器根据配置文件去创建实例并创建各个实例之间的依赖关系 核心:bean工厂:在 ...
- Spring MVC工作原理 及注解说明
转载自 http://blog.csdn.net/shuyeshangdemayi/article/details/50259493 SpringMVC框架介绍 1) Spring MVC属于Spr ...
最新文章
- SDCC 2016 中国软件开发者大会盛大开幕
- [转]Linux 进程间通信:共享内存
- C语言实现随机快速排序random quick sort算法(附完整源码)
- Boson NetSim实验模拟器破解
- python 完全面向对象_python 面向对象(一)
- 记录所遇到的编译错误及解决方法
- LeetCode 1020. 飞地的数量(图的BFS/DFS)
- GitHub博客开发上线实战
- 分布式SQL学习总结(2)——TiDB 的现在和未来
- 在VB中如何让背景图片铺满整个MDIForm
- C++ STL 文件内容的显示和追加
- jstree静态生成树并为树添加触发事件
- html中字体 楷体_html常用的字体样式
- html的abbr标签,html标签里有个abbr 请问这个标签是肿么使用的
- Java基于ssm的超市多商家系自提系统
- SEO的工作内容是什么?
- JS跳转到第三方地图APP
- Mac中QQ消息记录丢失的问题解决
- 10g数据库入门与实践 oracle_oracle10g数据库入门与实践
- seo原创工具_网站seo需要用到哪些工具,seo工具大全
热门文章
- linux安装virtualbox命令,在Linux中从命令行查找Virtualbox Version的方法
- linux io重定向指令,Linux基础知识之 IO重定向
- python ui自动化配置文件,Python+Selenium进行UI自动化测试项目中,常用的小技巧2:读取配置文件(configparser,.ini文件)...
- E数据结构实验之查找五:平方之哈希表
- SpringBoot WebSocket Stomp
- 机器学习实战笔记(Python实现)-02-k近邻算法(kNN)
- Vue.js Class 与 Style 绑定
- Java性能优化指南,及唯品会的实战
- 从零开始学习jQuery (七) jQuery动画-让页面动起来!
- 用matlab实现感知机学习算法,训练分类器并解决井字游戏