读书人

Hibernate(21):getCurrentSession仍是

发布时间: 2012-11-19 10:18:51 作者: rapoo

Hibernate(21):getCurrentSession还是用openSession?

??? 从Hibernate(十九): 异常"Session was already closed"开始的,连着几遍针对"Session was already closed"问题的持续跟踪, 在上篇Hibernate(20):默认情况下决定commit时session命运的三个条件里最终找到了源头. 路途虽说艰辛,但收获还是不小, "拔萝卜带出泥"地引出了一系列Hibernate世界里的基本构架. 在接下来,我们先来看getCurrentSession与openSession有什么区别.
--------------------
???我们知道, 一般来说, 为了使用Session, 可以有两种方式:调用SessionFactory的getCurrentSession或openSession. 那么这两个方法有什么不同?使用时有什么注意点? 再往深地说, 这样的设计对于我们有什么借鉴之处?

???好像是Hibernate以前的版本里没有getCurrentSession方法, 它是后来新加的(文档中有这样的描述: Startingwith version 3.0.1, Hibernate added theSessionFactory.getCurrentSession() method). 为什么要加呢?Hibernate自己的文档里有这方面的介绍, 这里就不copy/paste到这了. 总的一个核心思想就是想达到"ContextualSessions"效果. 这个效果是通过一个接口org.hibernate.context.CurrentSessionContext来实现的,一般最常用的是它的实现类org.hibernate.context.ThreadLocalSessionContext.对应的配置是,hibernate.cfg.xml文件中的<propertyname="current_session_context_class">thread</property>.

??? 配置是这样的, 那么具体在代码层面又是怎么实现的? 我们从SessionFactory的getCurrentSession方法说起,照应题目中的疑问,先看从getCurrentSession的实现来看其的好处.

??? 在这个方法中, 首先判断有没有配置currentSessionContext,如有的话,再调用currentSessionContext的currentSession方法. 那么这个currentSessionContext 是什么时候创建的??
???在SessionFactory(实现类SessionFactoryImpl)的构造方法中, 我们找到一句:currentSessionContext =buildCurrentSessionContext();在buildCurrentSessionContext方法中,hibernate从配置文件中取出current_session_context_class信息,(此方法中有个transactionManager的问题,这里先不讨论),据这个current_session_context_class是否为jta或thread或managed相应创建Hibernate内置org.hibernate.context.CurrentSessionContext接口的实现类JTASessionContext或ThreadLocalSessionContext或ManagedSessionContext.另外,buildCurrentSessionContext方法还支持自定义的CurrentSessionContext接口实现,这里也不做介绍.

??? 这里我们直接进到ThreadLocalSessionContext实现类的currentSession方法,这个也就是SessionFactory的getCurrentSession最终要调用的方法.

???首先第一句是existingSession( factory ), 这个没啥可说的,它是想从ThreadLocal里取出与传入的factory 相对应的Session.如果没有,就调用buildOrObtainSession,总觉得这个方法有些歧义,看它的实现发现实际上是new了一个Session,而没有什么Obtain,new一个session是通过SessionFactory的openSession(final Connection connection,
finalboolean flushBeforeCompletionEnabled,final booleanautoCloseSessionEnabled,final ConnectionReleaseModeconnectionReleaseMode)方法.这里的autoCloseSessionEnabled也就是ThreadLocalSessionContext类里写死的isAutoCloseEnabled方法,也就是它最终导致了t.commit()后session.close时,"Session wasalready closed"异常的抛出.

???再看current.getTransaction().registerSynchronization( buildCleanupSynch())一句, 第一次见registerSynchronization方法, 它是干啥的?要给跟刚才通过buildOrObtainSession方法新建的Session绑定一个javax.transaction.Synchronization实现. 这里看到是绑定了一个unbind( factory )方法,看样子是在事务结束后将ThreadLocal里绑定的session去除掉.(是不是也正是这个registerSynchronization方法, 才有了三个条件中的callback为true了?日后再进一步观察验证).

???接下来是是否对新建session是否要做代理wrap的判断和相应处理.(这样也就解决了为什么debug跟踪时session.save方法时总先要执行ThreadLocalSessionContext.TransactionProtectionWrapper类里invoke方法,一个新问题:从TransactionProtectionWrapper的名字看是要做"事务保护",那么这个事务保护又是怎么实现的?若不保护又怎样?这两个问题先放着)

??? 再接下来就是通过执行doBind方法将新建的session绑定到ThreadLocal了.

??? 这篇中,引出问题后,从getCurrentSession的实现看到有如下好处:
?? ???? 1, 如果ThreadLocal里已有,就不必再新建session,这样也就为session的方便获取做好的铺垫.
?? ???? 2, 若新建session,对其对应的Transaction做了registerSynchronization,这里做了unbind( factory )处理.
?? ???? 3, 若新建session,视情况再做代理封装,这里封装为TransactionProtectionWrapper.
??? 下一篇中, 我们将看openSession有什么优势?

读书人网 >软件架构设计

热点推荐