解析Spring托管下Hibernate Session的生命周期
来源:互联网 发布:linux vi 替换命令 编辑:程序博客网 时间:2024/05/17 07:13
一、Session生命周期的影响因素
Hibernate Session的生命周期受到其自身属性和方法的影响,简单的说:
SessionFactory的openSession() 方法会开启一个session。
Session的flushMode会决定session何时进行flush。
Session的flush()方法会对session进行强制flush。
Session的close()方法会关闭session。
然而在Spring托管中,session并不是程序员自己控制的,session的生命周期交由Spring管理。影响session生命周期的情况有这几种:
使用SessionFactory.getCurrentSession()方法。
使用HibernateTemplate来屏蔽对session的直接访问。
使用HibernateTransactionManager,并在session使用区域外围包装了本地事务,甚至是事务嵌套。
使用了JtaTransactionManager,并在session使用区域外围包装了Jta事务,甚至是事务嵌套。
使用了OpenSessionInViewFilter。
以上情况都对Session的open时间, flushMode, flush时间和close时间有影响。
二、SessionFactory.getCurrentSession()
查看SessionFactoryImpl可以看到,此方法从CurrentSessionContext中获取存在其中的session。在非 Spring环境下,CurrentSessionContext的实现是由 “hibernate.current_session_context_class”属性来控制的。但是在Spring环境 下,CurrentSessionContext的实现则变成了 SpringSessionContext或者SpringJtaSessionContext 。
getCurrentSession() { //详细代码请看org.hibernate.internal.SessionFactoryImpl:getCurrentSession return currentSessionContext.currentSession();} // SpringSessionContext// 详细代码请看org.springframework.orm.hibernate4.SpringSessionContext:currentSession currentSession() { session = map.getSessionByKey(this.sessionFactory); if(session == null && existTransaction) { session = this.sessionFactory.openSession(); if(currentTransaction.readOnly) session.setFlushMode(MANUAL); else session.setFlushMode(AUTO); map.setSessionByKey(this.sessionFactory, session); } return session;}
上面的伪代码中,假设map是一个存储SessionFactory <-> session的地方(后面会分析map的具体实现和用途),currentSession方法会返回:
已有的session。
新建的session (当前没有session,并且存在transaction)。并把FlushMode设置为AUTO或者MANUAL(For readonly)。
throws exception (当前没有session,也没有transaction)。
1、HibernateTemplate
包装在HibernateTemplate中的session会受到Transaction的影响。
doExecute(callback) {// 查看org.springframework.orm.hibernate4.HibernateTemplate:doExecute try{ session = sessionFactory.getCurrentSession(); }catch (e){} if(session==null) { session = sessionFactory.openSession(); session.setFlushMode(MANUAL); isNew=true; } callback.invoke(); if(isNew) session.close();}
由上面伪代码可以看出,在已经存在session或者transaction的环境下,session不受HibernateTemplate 的任何影响。如果当前不存在session和transaction,getCurrentSession会抛出exception。 HibernateTemplate会开启一个新的session,并把flushMode设为MANUAL,最后在callback结束后会关闭新建的 session。
2、HibernateTransactionManager
HibernateTransactionManager为本地事务管理器,它不支持分布式数据源,它将事务交给了 openSession(), session.commint()和session.rollBack()。任何一个声明了@Transactional的方法,都会被 org.springframework.transaction.interceptor.TransactionInterceptor做AOP切 割。其父类的方法invokeWithinTransaction执行了一个transaction。
invokeWithinTransaction(invocation) {// org.springframework.transaction.interceptor.TransactionAspectSupport tranInfo = createTransactionIfNecessary(); transactionManager.doBegin(tranInfo); invocation.proceed(); transactionManager.doCommit(tranInfo); transactionManager.doCleanupAfterCompletion(tranInfo); }
上面transactionManager是类HibernateTransactionManager的实例,且 doBegin,doCommit与doCleanupAfterCompletion为类中的三个方法。上面伪代码中的四行代码对session的生命 周期至关重要。
createTransactionIfNecessary方法会创建一个包装好的transaction,它包含了所有 transaction所需要的信息。但它不是UserTransaction和JDBC transaction,所以它只是一个虚拟的transaction实例。transaction实例会查看是否已经存在session或者 connection,如果有,则将其存入自己的域中。
第一步中生成的transaction是否已经存在session, 如果已经存在则跳过。如果没有,真正调用SessionFactory的openSession方法,flushMode设为AUTO。
先调用session.flush(), 再调用session.commit().
释放connections。如果session是在第2步中新创建的,则执行session.close()或者注册一个deffer close(OpenViewInFilter中的isSingleSession=false),否则什么也不做。
3、JtaTransactionManager
在JTA事务下,userTransaction与session在表层代码上不存在任何联系。session的生命周期是如何跟 userTransaction绑定在一起的呢?它们之间的桥梁在 org.springframework.transaction.support.TransactionSynchronizationManager。 TransactionSynchronizationManager中定义的都是ThreadLocal变量,保存了当前线程中正在运行的 Transaction信息,以及SpringSessionSynchronization的实例。 TransactionSynchronizationManager中都是静态方法,提供对变量的访问。
每一个SpringSessionSynchronization的实例中均保存了一对sessionFactory和session,并提供了对session的操作方法。我们不需要关心这些方法,这些方法都是由TransactionManager自动调用的。
从下面一段代码出发,我们看看TransactionManager都做了什么。
@Transactional public void transfer( amount, form, to) { Session sessionA = this.sessionFactoryA.getCurrentSession(); Account a = sessionA.load(Account.class,from ); a.setAmount(a.getAmount()-amount); Session sessionB = this.sessionFactoryB.getCurrentSession(); Account b = sessionB.load(Account.class, to); b.setAmount(b.getAmount()+amount);}
方法会被TransactionIntercepter切割。这部分的原代码同HibernateTransactionManager是相同的,但为了便于理解,我将改变一下伪代码:
// org.springframework.transaction.interceptor.TransactionAspectSupportinvokeWithinTransaction(invocation) { tranInfo = createTransactionIfNecessary(); transactionManager.doBegin(tranInfo) // 包含在源码createTransactionIfNecessary()中,这里拎出来单说 invocation.proceed(); transactionManager.triggerBeforeCommit(); transactionManager.doCommit(tranInfo); // 包含在源码commitTransactionAfterReturning()中 transactionManager.triggerBeforeComplete() transactionManager.doCleanupAfterCompletion(tranInfo); // 包含在源码commitTransactionAfterReturning()中}
在执行方法前,intercepter会使用JtaTransactionManager启动一个UserTransaction,并设置TransactionSynchronizationManager中的状态,表明线程处在Transaction中。
sessionFactoryA.getCurrentSession()会使用已经存在的session,如果不存在,则调用 openSession()创建一个新的session,flushMode设为AUTO。创建一个 SpringSessionSynchronization,将sessionA和sessionFactoryA放入其中。最后调用TransactionSynchronizationManager.registerSynchronization(springSessionSynchronization), 把SpringSessionSynchronization放入 TransactionSynchronizationManager 的synchronization集合中。 此段的源代码可以查看 org.springframework.orm.hibernate3.SessionFactoryUtils:doGetSession()。
sessionB的创建过程与步骤2相同,只是它拥有自己的SpringSessionSynchronization。
在triggerBeforeCommit()方法中,会循环取出 TransactionSynchronizationManager下的SpringSessionSynchronization,并调用它的beforeCommit方法,里面会对其包含的session进行flush。
doCommit方法执行userTransaction的commit。
triggerBeforeComplete方法会循环调用SpringSessionSynchronization的 beforeComplete方法,如果session是在当前事务创建的,则调用它的close或defer close。如果是事务之前早已存在的session,则不进行close,只释放connection。
4、OpenSessionInViewFilter
无论是在JTA还是本地事务情况下,有几个sessionFactory实例,就应该声明多少个OSIF。每一个OSIF对应一个sessionFactory,这样才能为每一个sessionFactory都提前创建一个session。
OSIF下有一个属性isSingleSession,如果为true,则整个request中,相同的sessionFactory下只创建 一个session,并一直保持到filter结束。如果isSingleSession值为false,OSIF不会创建session,它只会声明在 此线程中每个transaction中创建的session,都使用defer close。也就是在filter结束的时候才会close。
三、总结
以代码为比对:
@Transactionalpublic void action() { Session s = sessionFactory.getCurrentSession(); ... ... }// with HibernateTemplate@Transactionalpublic void action() { this.hibernateTemplate.save(); }
使用OSIF(isSingleSession=true)使用OSIF(isSingleSession=false)不用OSIF 在HibernateTransactionManager中
OSIF创建session,FlushMode可配置 。
事务边界获取已有session。
事务开始。
进入action()。
获取已有session。
执行操作。
退出action()。
事务边界。
自动flush session。
事务提交。
OSIF中关闭session。
OSIF开启defer close。
事务边界创建新session(FlushMode=AUTO)。
事务开始。
进入action()。
获取已有session。
执行操作。
退出action()。
事务边界
自动flush session。
事务提交。
OSIF中关闭所有session。
事务边界创建新session(FlushMode=AUTO)。
事务开始。
进入action()。
获取已有session。
执行操作。
退出action()。
事务边界
自动flush session。
事务提交。
自动关闭session。
在HibernateTransactionManager与 HibernateTemplate 中同上
同上同上在JtaTransactionManager中OSIF创建session,FlushMode可配置 。
事务开始。
进入action()。
获取已有session。
执行操作。
退出action()。
事务边界。
自动flush session。
事务提交。
OSIF中关闭session。
OSIF开启defer close。
事务开始。
进入action()。
获取已有session(FlushMode=AUTO)。
执行操作。
退出action()。
事务边界
自动flush session。
事务提交。
OSIF中关闭所有session。
事务开始。
进入action()。
创建新session(FlushMode=AUTO)。
执行操作。
退出action()。
事务边界
自动flush session。
事务提交。
自动close session。
在 JtaTransactionManager与HibernateTemplate中同上同上同上不在Transaction中,并使用HibernateTemplateOSIF创建session,flushMode可配 。
HibernateTemplate复用session。
session flush依赖template的flushMode属性。
OSIF关闭session。
HibernateTemplate创建session。
session flush依赖template的flushMode属性。
OSIF关闭session
- 解析Spring托管下Hibernate Session的生命周期
- Hibernate Session 的生命周期
- spring中延长hibernate中session的生命周期:OpenSessionInViewFilter
- Spring、Hibernate 事务流程分析-Session生命周期
- 备注在工作中SSH中将hibernate托管给spring获取session的方法
- spring与hibernate集成的session事务控制问题解析
- Hibernate学习--Session生命周期的不同状态
- hibernate session生命周期示例
- spring+hibernate的session问题
- spring+hibernate的session问题
- Spring+hibernate的session问题
- spring-OpenSessionInVies延长session的生命周期
- spring+hibernate多线程下session问题
- hibernte与spring结合时,配置使hibernate的session的生命周期延迟,以及配置httpsession的时间
- 在Spring托管的Hibernate中使用二级缓存
- hibernate session的常用方法解析
- hibernate session的常用方法解析
- 测试Hibernate中session的生命周期以及CRUD
- matlab生成dll copy by scudz
- JAVA中关于Map的九大问题
- Linux-shell exit code
- getFragmentManager与getChildFragmentManager,解决fragment白屏 、
- eclipse中maven项目修改
- 解析Spring托管下Hibernate Session的生命周期
- 创建一个成功的App前要考虑的5个要点
- No module named win32api
- VMware 虚拟机联网桥接模式和NAT模式上网设置
- Android Log详解(Log.v,Log.d,Log.i,Log.w,Log.e)
- 学习
- 琐碎知识点记录
- Practice Round APAC test 2017——Problem D. Sums of Sums
- 什么是wall clock time