[原理][源代码解析]spring中@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关系---转载
问题: 一. 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 save or update时,允许Hibernate 回调初始化时注册的 Spring SpringSessionContext 生成 HibernateSession ,进一步从连接池获取 jdbcConnection // 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)时 Session新建和Session获取都是在AbstractPlatformTransactionManager.getTransaction方法中完成的 对于@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 or get的时候获取不到Session,不正常抛错 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). 有一个允许就正常执行返回了Session. 两个有一个开启(ture)就不抛错,正常执行返回Session. 何时allowCreate是ture?见下面 三. 那么何时可以获取非事务类型的Session? . closeSession(session); throw new IllegalStateException("No Hibernate Session bound to thread, andconfiguration does not allow creation of non-transactional one here"); } 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挂起和恢复的操作.具体详见代码.
原文地址:http://blog.csdn.net/fei33423/article/details/32346821
[原理][源代码解析]spring中@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关系---转载的更多相关文章
- [原理][来源解析]spring于@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关联
Spring 捆绑Hibernate. 夹: 一. 1. Spring 怎样处理propagation=Propagation.SUPPORTS? 2. Spring 何时生成HibernateSe ...
- Spring中@Transactional用法深度分析
引言: 在Spring中@Transactional提供一种控制事务管理的快捷手段,但是很多人都只是@Transactional简单使用,并未深入了解,其各个配置项的使用方法,本文将深入讲解各个配置项 ...
- Spring中@Transactional用法
作者:bladestone 来源:CSDN 原文:https://blog.csdn.net/blueheart20/article/details/44654007 版权声明:本文为博主原创文章,转 ...
- Spring中@Transactional事务回滚
转载: Spring中@Transactional事务回滚 一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部 ...
- 源代码解析Android中View的layout布局过程
Android中的Veiw从内存中到呈如今UI界面上须要依次经历三个阶段:量算 -> 布局 -> 画图,关于View的量算.布局.画图的整体机制可參见博文 < Android中Vie ...
- 使用具体解释及源代码解析Android中的Adapter、BaseAdapter、ArrayAdapter、SimpleAdapter和SimpleCursorAdapter
Adapter相当于一个数据源,能够给AdapterView提供数据.并依据数据创建相应的UI.能够通过调用AdapterView的setAdapter方法使得AdapterView将Adapter作 ...
- 全面解析Spring中@ModelAttribute注解的用法
本文不再更新,可能存在内容过时的情况,实时更新请移步我的新博客:全面解析Spring中@ModelAttribute注解的用法: @ModelAttribute注解用于将方法的参数或方法的返回值绑定到 ...
- Spring中@Transactional事务回滚(含实例具体解说,附源代码)
一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用. 以下举个栗子:比方一个部门里面有非常多成员,这两者分别保存在部门表和成员表里面,在 ...
- Spring中@Transactional事务回滚实例及源码
一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除 ...
随机推荐
- java1.8的几大新特性(一)
一.接口的默认方法与静态方法,也就是接口中可以有实现方法 public class Test { public static void main(String[] args) { Formula a= ...
- windows 上rails3.2 + ruby1.9环境搭建
题外话:本文是通过参考网友资料,亲自尝试过后写的,有不对之处,还请网友指正! 1.搭建环境 准备ruby1.9.3 下载地址: 下载地址:http://rubyforge.org/frs/?group ...
- Xcode 配置常用变量(SRCROOT, PROJECT_DIR, PROJECT_NAME)
https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/ ...
- 致改变——总结&规划(2016·一)
今天是立夏,过完这一天意味着农历2016年的第一季度已经过去了,也意味着真正的夏天已经来了.如果说春天是作物的播种期的话,那夏天可以看做是作物的成长期,也是农民伯伯们最繁忙的时期.本文主要对自己过去的 ...
- HTTP缓存是如何实现
浏览器是如何知道使用缓存的,其实这都是通过http中,浏览器将最后修改时间发送请求给web服务器,web服务器收到请求后跟服务器上的文档最后修改的时间对比,如果web服务器上最新文档修改时间小于或者等 ...
- 在 ASP.NET MVC 中创建自定义 HtmlHelper
在ASP.NET MVC应用程序的开发中,我们常碰到类似Html.Label或Html.TextBox这样的代码,它将在网页上产生一个label或input标记.这些HtmlHelper的扩展方法有些 ...
- Android中界面实现全屏显示的两种方式
在开发android的应用当中,我们会遇到将一些界面设置为全屏显示的格式,有两种实现的方法.其一是在Java代码中实现,其二是在配置文件中实现. 1. 在Java代码中设置 super.onCreat ...
- 使用Flashbuilder/Flashbuilder-plugins搭建Flex工程每日构建(自动化构建)的方法
前段时间研究flex工程自动编译的时候,遇到了阻碍,就放下了,直到今天每日构建的问题又一次给项目组带来了麻烦,于是我彻底愤怒了. 最后,我的怒火没有白费,写出来以发泄情绪. [基本原理]: adobe ...
- bzoj 1878 [SDOI2009]HH的项链(离线处理+BIT)
Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此, 他的项链变 ...
- spoj 7258 SUBLEX(SAM,名次)
[题目链接] http://www.spoj.com/problems/SUBLEX/en/ [题意] 给定一个字符串,询问次序为k的子串. [思路] SAM,名次 建好SAM后求出每个结点根据tra ...