[原理][来源解析]spring于@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关联
Spring 捆绑Hibernate.
夹:
一、
1. Spring 怎样处理propagation=Propagation.SUPPORTS?
2. Spring 何时生成HibernateSession ?
3. propagation=Propagation.SUPPORTS和propagation=Propagation.require对生成Session有何影响,共同点和差别 ?
3.1. 未配置@Transaction和 配置@Transaction(propagation=Propagation.SUPPORTS)对生成Session有何影响,共同点和差别?
4. Spring 何时从线程池中获取到jdbcconnection 设置setAutoCommit(false)?
二、 两种无Session情况下获取Session情况,一种抛错,一种正常
三、 那么何时能够获取一个non-transactional Session?
|
问题: 一. 1. Spring 怎样处理propagation=Propagation.SUPPORTS? 2. Spring 何时生成HibernateSession ? 3. propagation=Propagation.SUPPORTS 和propagation=Propagation.require对生成Session有何影响 ? 共同点:都会进入aspect切面处理, 试图新建Session,开启Transaction ,都能获得.TransactionStatus 差别: 前者成功开启事务,后者未开启,但会设置一个同意懒惰载入Session的配置.详情见以下代码. 3.1. 未配置@Transaction 和 配置@Transaction(propagation=Propagation.SUPPORTS)的差别? 共同点: 都没有起事务. 不同点: 前者不会进入aspect切面处理, 后者进入试图新建Session,开启事务但未成功,会设置一个同意懒惰载入Session的配置. 详情见以下代码 4. Spring 何时从线程池中获取到 jdbcconnection 设置 setAutoCommit(false)? |
|
正文解析: spring是在TransactionAspectSupport(切面编程)的createTransactionIfNecessary方法中完毕对@Transactional注解的处理. 然后托付给PlatformTransactionManager实现类的getTransaction()方法( 实现 类是HibernateTransactionManager被我们配置在application.xml中)对propagation=Propagation.SUPPORTS的处理也是在这种方法内实现,详细是其父类AbstractPlatformTransactionManager.getTransaction()中. 代码片段例如以下: AbstractPlatformTransactionManager.getTransaction(TransactionDefinitiondefinition){ Object transaction = doGetTransaction(); //注1: springframework的HibernateTransactionObject 实例,内部持有的是 HibernateSession ,一開始是Null; . . otherCode . . // No existing transaction found -> check propagationbehavior to find out how to proceed. if (definition.getPropagationBehavior()== TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transactionmarked with propagation 'mandatory'"); } else if (definition.getPropagationBehavior()== TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() ==TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() ==TransactionDefinition.PROPAGATION_NESTED) { SuspendedResourcesHolder suspendedResources = suspend(null); if (debugEnabled) { logger.debug("Creating new transaction withname [" + definition.getName() + "]:" + definition); } try { boolean newSynchronization =(getTransactionSynchronization() != SYNCHRONIZATION_NEVER); DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true,newSynchronization, debugEnabled, suspendedResources); doBegin(transaction, definition); // 注2: 生成 HibernateSession ,然后获取jdbcconnection , 而且Connection,setAutoCommit(false),开启我们理解上的sql事务.详细是调用Session持有的HibernateJDBCTransaction中的.begin()方法中, prepareSynchronization(status,definition); //设置SpringTransactionSynchronizationManager.initSynchronization(). return status; } catch (RuntimeException ex) { resume(null, suspendedResources); throw ex; } catch (Error err) { resume(null, suspendedResources); throw err; } } else { // 注3 这个流程就是当”线程中无事务,且配置是propagation= Propagation.SUPPORTS”时运行的路径.这一步未生成Hibernate Session, jdbc Connection.但 prepareTransactionStatus()中做了一步操作,设置SpringTransactionSynchronizationManager.initSynchronization().正是这个操作在之后,我们 才干在后来Hibernate // Create "empty" transaction: no actualtransaction, but potentially synchronization. boolean newSynchronization = (getTransactionSynchronization()== SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus(definition, null, true,newSynchronization, debugEnabled, null); } . . . } 注2和注3解答了2,3问题. 对以上代码中命名的一点看法: l getTransaction返回TransactioStaus, 感觉用 getTransactioStaus比 spring眼下的命名getTransaction更合适 或者取名 getTransactionIfNecessary比較好的,依据注3可知,此分支并没有真正的开启数据库事务.更没有获取jdbc Connection.和不论什么生成 Hibernate Session. l 比較重要的几个类Springframework的HibernateTransactionObject,Hibernate的Session,Hibernate的JDBCTransaction,jdbc的Connection. Springframework HibernateTransactionObject持有一个 Hibernate Session, Hibernate Session持有一个Hibernate JDBCTransaction , 终于持有 jdbc Connection. 由于 数据库事务Connection.setAutoCommit(false).事务开启是附属于Connection. Connection应该是先于事务开启. 所以感觉用Springframework HibernateTransactionObject 和Hibernate JDBCTransaction 持有 jdbc Connection不同合理. 取名为 Springframework HibernateTransactionStatusObject , Hibernate JDBCTransactionStaus更合理. 对于第4个问题. 对于@Transaction(propagation=Propagation.REQUIRE)时 对于@Transaction(propagation=Propagation.SUPPORTS) , 当懒惰获取完Session后,当且仅当真正尝试数据库操作时才会懒惰获取Connection. 获取Connection的简单堆栈例如以下. ConnectionManager.openConnection()line: 446 //注:发现没有连接,从线程池获取一个连接 ConnectionManager.getConnection()line: 167 BatchingBatcher(AbstractBatcher).prepareQueryStatement(String,boolean, ScrollMode) line: 161 EntityLoader(Loader).prepareQueryStatement(QueryParameters,boolean, SessionImplementor) line: 1700 |
|
问题: 二. 对于上面第3个小问题的延伸,注3表明此处并没有生成Session. 然后get or save 正常不报错. 我们定义为A情况. A.当处于propagation=Propagation.SUPPORTS时,未生成Session和获取到jdbc Connection.当我们 save or get 时候正常不报错. 以下看下无Session情况下获取Session的第二种情况: B.我们可能遇到过这种错误:No Hibernate Session bound to thread,and configuration does not allow creationof non-transactional one here.错误原因是我们save A和B都是在无Session情况下获取Session, 为什么一个正常,一个不正常? |
|
正文解析: 详细代码片段例如以下: SpringSessionFactoryUtils.doGetSession(SessionFactory sessionFactory,InterceptorentityInterceptor,SQLExceptionTranslator jdbcExceptionTranslator,booleanallowCreate){ if (TransactionSynchronizationManager.isSynchronizationActive()){ // 注4:A情况下返回是true,原因见注3,B情况下返回是false. // 注: 此部分代码实现了”假设眼下没有Session那么就生成Session”的逻辑 } if ((!(allowCreate)) && (!(isSessionTransactional(session,sessionFactory)))) { // 注5: 两个开关推断. allowCreate 对于HibernateManager是强制设置为false(关闭)的,后者正是前面HibernateManager处理@Transaction时开启(返回true). 何时allowCreate是ture? 见以下 三. 那么何时能够获取非事务类型的Session? . closeSession(session); throw new IllegalStateException("No Hibernate Session bound to thread, andconfiguration } return session; //注6, 假设没有被注5禁止,那么就返回生成的Session } 注4,注5解答了上述问题. 所以出现B问题, 检查下自己的代码,是否处于事务环境中. 因为getTransaction()会把Session绑定到ThreadLocal中,假设新建了独立线程, 注意内部调用的代码是否加上@Transaction,不然该线程中是无法获取到Threadlocal的Session变量. 对于这个Exception.后半部分”configuration does notallow creation of non-transactional one here”的详细语义.是指”configuration不同意生成一个非事务类型的Session”. |
|
三. 那么何时能够获取非事务类型的Session? |
|
1. 查看源码能够发现OpenSessionInViewFilter中能够 (配置在 web.xml中),正是这个allow=true ,才使其在无事务环境下先生成一个Session,并延迟关闭.保证了view层能够获取到懒惰载入的实体. 2. 还有就是Spring 提供的HibernateTemplate 模板工具类中也是allow=true,方便我们运行Hibernate方法. 其它如propagation= Propagation.require_new也是在上述的代码中,进行原connection挂起和恢复的操作.详细详见代码. |
其它如propagation =Propagation.require_new也是在上述的代码中,进行原connection挂起和恢复的操作.详细详见代码.
版权声明:本文博主原创文章,博客,未经同意不得转载。
[原理][来源解析]spring于@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关联的更多相关文章
- [原理][源代码解析]spring中@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关系---转载
问题: 一. 1. Spring 如何处理propagation=Propagation.SUPPORTS? 2. Spring 何时生成HibernateSession ? 3. propagati ...
- spring事务管理出错。No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy ...
- spring事务-说说Propagation及其实现原理
前言 spring目前已是java开发的一个事实标准,这得益于它的便利.功能齐全.容易上手等特性.在开发过程当中,操作DB是非常常见的操作,而涉及到db,就会涉及到事务.事务在平时的开发过程当中,就算 ...
- Spring提取@Transactional事务注解的源码解析
声明:本文是自己在学习spring注解事务处理源代码时所留下的笔记: 难免有错误,敬请读者谅解!!! 1.事务注解标签 <tx:annotation-driven /> 2.tx 命名空间 ...
- Spring中@Transactional用法
作者:bladestone 来源:CSDN 原文:https://blog.csdn.net/blueheart20/article/details/44654007 版权声明:本文为博主原创文章,转 ...
- Spring中@Transactional用法深度分析
引言: 在Spring中@Transactional提供一种控制事务管理的快捷手段,但是很多人都只是@Transactional简单使用,并未深入了解,其各个配置项的使用方法,本文将深入讲解各个配置项 ...
- Spring源码学习之:spring注解@Transactional
在分析深入分析@Transactional的使用之前,我们先回顾一下事务的一些基本内容. 事务的基本概念 先来回顾一下事务的基本概念和特性.数据库事务(Database Transaction) ,是 ...
- Spring 注解@Transactional
Spring事务的传播行为 在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例 ...
- Spring中@Transactional事务回滚实例及源码
一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除 ...
随机推荐
- Tip.It诞生记
灵光一闪 之所以想做 Tip.It,完全是受自己初到北京时找房子各种痛苦的启发,当时为了跳过中介租房子,去58同城,豆瓣等各种网站去看房子,比如说下图就是一个典型的58同城的租房页面. 可以看到电话号 ...
- 数据挖掘之分类算法---knn算法(有matlab例子)
knn算法(k-Nearest Neighbor algorithm).是一种经典的分类算法.注意,不是聚类算法.所以这种分类算法 必然包括了训练过程. 然而和一般性的分类算法不同,knn算法是一种懒 ...
- 【JSP动态网站】JDBC连接SqlServer 2008数据库
JSP程序需要通过JDBC接口才能访问数据库. 启动MyEclipse,选择“Window”→“Open Perspective”→“MyEclipse Database Explorer”菜单项,打 ...
- linux(边压缩边传输边解压)
比如我要转移旧VPS /home/wwwroot 下的web目录到新VPS(123.123.123.123)的/home/wwwroot 目录下 1.进入目录 cd /home/wwwroot ...
- iOS 创建推送证书
1.首先你想创建推送证书和以前你做真机测试证书一样,需要实现准备一个99$的付费账号.然后登陆苹果开发者网站.http://developer.apple.com/ 2.登陆以后你能看到这个界面然后选 ...
- windows7旗舰版下载出现蓝屏代码50怎么办?
windows7旗舰版下载出现蓝屏代码50怎么办?电脑蓝屏BCCode:50. 问题事件名称: BlueScreen OS 版本: 6.1.7601.2.1.0.256.1 区域设置 ID: 2052 ...
- 最少步数(dfs + bfs +bfs优化)
最少步数 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 这有一个迷宫,有0~8行和0~8列: 1,1,1,1,1,1,1,1,1 1,0,0,1,0,0,1,0,1 ...
- Yii2权威指南中文版及众包翻译平台
Yii2在今年4月份公布了beta版本号,预计下半年会推出正式版本号(可用于生产环境). Yii2使用了新的PHP语法特性(PHP5.4+)并集成了大量新的编程最佳实践, 如命名空间.响应式界面组件库 ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- ZCTF-ARM64-Re300
Re300-arm64 是一个64位的ARM程序.使用IDA加载,蹦出来这个框框,就是说IDA6.6还没有对ARM64位的程序实现relocation的分析. 就是由于这个,所以连对l ...