用Hibernate的人都知道Hibernate最原始的使用Session方式(异常忽略):
获取SessionFactory
打开Session
打开事务(可选)
执行操作
关闭事务(可选)
关闭Session
|
当然还有另外一个方法getCurrentSession()
这个方法就是通过SessionContext来减少Session创建的。比如常用的ThreadLocalSessionContext:
Session current = existingSession( factory );
if (current == null) {
current = buildOrObtainSession();
current.getTransaction().registerSynchronization( buildCleanupSynch() );
if ( needsWrapping( current ) ) {
current = wrap( current );
}
doBind( current, factory );
}
return current;
currentSession()内部先从ThreadLocal中获取Session。若不为null直接返回,若为null则openSession(...)一个Session并把这个Session对象绑定在ThreadLocal上。它就是通过在ThreadLocal中注册绑定Session来确保线程中最多只有一个Session对象。
=====================================================
Spring提供许多Template对各种底层ORM等进行集成,如JdbcTemplate、HibernateTemplate、JpaTemplate等同时也提供了相应的Dao模板类,如JdbcDaoSupport、HibernateDaoSupport、JpaDaoSupport等
既然说Spring对Hibernate的集成,就得看HibernateTemplate和HibernateDaoSupport这两个类。
使用HibernateDaoSupport进行数据操作时常用两种方式访问Session:getSession()和HibernateCallback。
注意:使用HibernateDaoSupport时候、如果再通过SessionFactory进行getCurrentSession()获取Session的话就有可能出现
问题了。因为 Spring的Bean工厂把Hibernate的SessionFactory动了点小手脚 ~
. 就是前面说前面说到的ThreadLocalSessionContext被Spring替换为 SpringSessionContext
!
这个SpringSessionContext的currentSession()方法核心如下:
return (org.hibernate.classic.Session) SessionFactoryUtils.doGetSession(this.sessionFactory, false );
// 这个false硬性规定doGetSession如果在线程中获取不到Session不自动创建Session
SessionFactoryUtils#doGetSession()是通过TransactionSynchronizationManager来获取Session资源的,
doGetSession()会通过 TransactionSynchronizationManager访问线程资源、但是整个操作中没有打开事务的话、
此方法会抛出异常:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
这个异常就是出现在 SessionFactoryUtils#doGetSession()方法的最后:
if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {
closeSession(session);
throw new IllegalStateException("No Hibernate Session bound to thread, " +
"and configuration does not allow creation of non-transactional one here");
}
|
getSession和getCurrentSession实现过程差不多,但是精简了SessionContext那一段。并且可以设置allowCreate,如果设置为false,此方法应该和getCurrentSession同样效果。
了解了这些之后、我进行了一个HibernateTemplate和getSession之间的测试,主要就是测试
单线程下多次重复请求创建Session与事务之间的关系、HibernateTemplate和getSession()两者之间在功能实现和效率上有什么样的不同。
Dao层: |
testTS()方法——临时创建用于测试的方法
通过HibernateTemplate和直接getSession等方法获取Session并保存
打印已经保存的Session的状态
打印已经保存的Session之间是否相同
打印SessionFactory的状态记录 |
Service层: |
testTS()方法——临时创建用于测试的方法
内部代码为执行三次请求:
getDao().testTS();
getDao().testTS();
getDao().testTS(); |
第一次测试
Service层的testTS(e)方法不打开事务
单线程
使用HibernateTemplate
|
结论:
Service层没有打开事务,但是每次操作CURD操作时,HibernateTemplate都会自动创建
Transactional。同一线程获取到的前后两个Session之间互不相同。
|
--------------Closed Transactional && Single-Thread--------------
Last Session Status : false //每次Session使用完自动关闭
This Session Status : false
Compared Session : false
测试数据扩大100倍并记时:
REQUEST[100]
Opened Session Count :300
Transaction Count :600 //我没有声明打开事务啊!为什么它还为我打开事务
Connection Count :300
---------------------------------------
TIME : 1719
|
第二次测试
Service层的testTS(e)方法打开事务
单线程
使用HibernateTemplate
|
结论:
在事务边界内获取的Session由Spring管理、不必手动关闭
虽然打开了事务,但是同一线程下同一事务边界内前后获取的两个Session仍然不同! 这是为什么???
后面会继续剖析HibernateTemplate源码,给出解释
|
--------------Open Transactional && Single-Thread--------------
Last Session Status : Open //每次Session使用完之后未关闭
This Session Status : Open
Compared Session : false //同一线程同一个事务前后获取的两个Session还不同!!!!!为什么?????
测试数据扩大100倍并记时:
REQUEST[100]
Opened Session Count :100
Transaction Count :200
Connection Count :100
---------------------------------------
TIME : 1719
|
第三次测试
Service层的testTS(e)方法不打开事务
单线程
使用getSession()
|
可以看到getSession()由于缺少Spring的支持,在无事务环境下。
它为每个CURD请求创建了一个Session。并且更让人震惊的是,它好像为每个Session都创建了新
Connection 。这些Session使用之后,它也并不关闭。
|
--------------Closed Transactional && Single-Thread--------------
Last Session Status : Open
This Session Status : Open
Compared Session : false
测试数据扩大100倍并记时,令人极其震惊且极其坑爹的一幕出现了!我亲眼看到程序以一种
肉眼可见的速度
慢腾腾的执行一次又一次的循环,它竟然执行了一分钟!!!:
REQUEST[100]
Opened Session Count :300
Transaction Count :0
Connection Count :300
---------------------------------------
TIME : 53844
|
第四次测试
Service层的testTS(e)方法打开事务
单线程
使用getSession()
|
这个最容易让人理解、由于同一线程且在同一事务边界内,前后两个Session相同。并且也不会重复创建
Connection。
|
--------------Open Transactional && Single-Thread--------------
Last Session Status : Open //每次Session使用完之后未关闭
This Session Status : Open
Compared Session : True //同一线程前后获取的两个Session相同
测试数据扩大100倍并记时:
REQUEST[100]
Opened Session Count :100
Transaction Count :200
Connection Count :100
---------------------------------------
TIME : 1204
|
总结:
getSession()在事务边界内会通过TransactionSynchronizationManager获取Session资源,同一线程内它不会重复创建Connection
,
那些获取到的Session()不需要手动关闭。但是在无声明式事务环境下,它就会表现出极其坑爹的状况,它反复获取Connection,也不关闭Session。非常消耗资源
HibernateTemplate有一个安全且高效的Session环境,它的CRUD都是位于HibernateCallback内部,如果它的CRUD并没有位于事务之中,它会自己创建一个事务(Spring集成Hibernate时,所有的资源都是由TransactionSynchronizationManager管理的
)。同一个线程中它只需要一个Connection。Session也会在事务边界处自动关闭,程序员不需要关注此事(这个事务边界可能是@Transactional显式声明的也可能是HibernateTemplate#doExecute隐式声明的)。
在同一个事务边界内,两个HibernateTemplate操作内部的Session互也不相同这个问题可以在HibernateTemplate源码中找到答案:
protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNewSession, boolean enforceNativeSession)
throws DataAccessException {
......
Session session = (enforceNewSession ?
SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
boolean existingTransaction = (!enforceNewSession &&
(!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
if (existingTransaction) {
logger.debug("Found thread-bound Session for HibernateTemplate");
}
FlushMode previousFlushMode = null;
try {
previousFlushMode = applyFlushMode(session, existingTransaction);
enableFilters(session);
Session sessionToExpose =
(enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session)
);
T result = action.doInHibernate(sessionToExpose);
flushIfNecessary(session, existingTransaction);
return result;
......
}
红色部分可以看到HibernateTemplate中获取的Session不是原生的,而是代理的。那个代理类是一个比较简单的内部类,源代码位于HibernateTemplate类文件最下部分。
每次HibernateTemplate#doExecute执行时除非声明不使用代理类,Spring都会使用线程中的Session资源来创建代理。但是这个代理类的创建对性能的影响微不足道了,Spring这样做肯定有它的道理。
各位英雄好汉,不要乱投新手帖、隐藏贴奥。
咱琢磨了好几天的东西,你们高手们就不要否决了
分享到:
相关推荐
**Spring与Hibernate集成详解** 在Java企业级应用开发中,Spring和Hibernate是两个非常重要的框架。Spring是一个全方位的轻量级应用框架,提供了强大的依赖注入、AOP(面向切面编程)以及各种服务管理功能。而...
- Spring与Hibernate集成,通常使用Spring的HibernateTemplate或HibernateDaoSupport,提供事务管理和数据访问抽象,使得代码更简洁,事务控制更方便。 - Spring与Struts2集成,Spring可以作为Struts2的Action的...
总结来说,Spring集成Hibernate在MyEclipse环境下,主要是通过配置Spring的IoC容器和事务管理,结合Hibernate的ORM能力,实现高效的数据库操作。这个过程涉及到了项目结构、配置文件、实体类、DAO、Service等多个...
这篇博客“Spring之Spring2.5集成Hibernate3.6”主要探讨了如何将两个经典的开源框架——Spring 2.5和Hibernate 3.6进行整合,以实现数据持久化的高效管理。 Spring 2.5版本是Spring框架的一个重要里程碑,它引入了...
本文将详细探讨Spring与Hibernate的集成,特别是如何在集成环境中使用和管理`Session`。 首先,Spring作为一个轻量级的框架,提供了强大的依赖注入(DI)和面向切面编程(AOP)功能,它可以帮助我们解耦应用程序...
在"spring集成hibernate所需jar包"中,通常包含以下关键的库文件: 1. **Spring Framework**:这是Spring的核心组件,包括`spring-context`、`spring-beans`、`spring-aop`、`spring-jdbc`和`spring-orm`等模块。...
**Spring与Hibernate的集成** 常见的方式是使用Spring的HibernateTemplate或SessionFactoryBean,它们可以帮助我们管理SessionFactory和Session。Spring可以控制事务边界,实现事务的统一管理,确保数据的一致性。 ...
5. **使用Spring管理Hibernate Session**:通过Spring的HibernateTemplate或JPA的EntityManager进行数据库操作。 这样的集成使得开发人员可以利用Spring的IoC(Inversion of Control)和AOP能力,以及Hibernate对...
通过这种方式,Spring和Hibernate成功集成,使得我们可以利用Spring的IoC和AOP特性来管理事务,同时利用Hibernate进行高效的数据持久化操作。这种集成方式大大提高了代码的可维护性和开发效率,降低了系统的耦合度。
在Spring集成Hibernate的过程中,我们需要配置Spring的DataSource、SessionFactory以及Hibernate的实体类和映射文件。DataSource是连接数据库的桥梁,SessionFactory则负责创建Session对象,Session对象是执行数据库...
集成Spring和Hibernate的关键在于如何在Spring中管理Hibernate的SessionFactory和Transaction。这通常通过以下步骤实现: 1. **配置Hibernate**: 创建Hibernate的配置文件(如hibernate.cfg.xml),定义数据源、...
1. **依赖注入**:Spring 提供的 DI(Dependency Injection)机制可以帮助管理 Hibernate SessionFactory 和 Session 实例,避免手动创建和管理这些对象。在配置文件中定义 SessionFactory 的 Bean,然后通过注解或 ...
总的来说,这个入门实例旨在帮助初学者理解如何在没有使用注解的情况下,通过XML配置文件集成SpringMVC、Spring和Hibernate,完成一个简单的Web应用。虽然现在的最佳实践倾向于使用注解和Spring Boot,但理解非注解...
在Spring和Hibernate的整合中,Spring可以作为Hibernate的容器,管理SessionFactory和Transaction,这样我们就能够在Spring的管理下进行数据库操作。通过@PersistenceContext注解,Spring可以注入EntityManager,@...
总的来说,这个“Struts+Spring+Hibernate 集成实现的经典权限管理系统”提供了一个完整的解决方案,展示了如何在Java Web应用中有效地管理权限,同时也为开发者提供了一个学习和实践整合这三大框架的实例。...
本文将详细探讨如何在Spring集成的Hibernate环境中配置二级缓存,以及其背后的原理和实践。 首先,我们需要了解什么是二级缓存。在Hibernate中,一级缓存是每个Session内部的缓存,它自动管理实体的状态,当一个...
这个库可能包含了Spring的IoC容器、Hibernate的实体管理以及两者间的集成配置,使得开发者无需单独导入Spring和Hibernate的多个jar文件,减少了项目的依赖复杂性。 描述中提到的下载经历,反映了在开发过程中寻找...
Struts2、Spring和Hibernate是Java开发中三大主流的开源框架,它们分别专注于Web层、业务层和服务层的管理,组合使用可以构建出强大的企业级应用。这些框架的jar包是开发人员日常工作中必不可少的工具。 **Struts2*...
集成Hibernate和Spring需要在Spring的配置文件中配置Hibernate的相关信息,包括SessionFactory、DataSource等。例如,通过`<bean>`标签定义数据源、SessionFactory,并使用`<tx:annotation-driven>`开启基于注解的...
本主题将深入探讨Hibernate的编程式事务管理和Spring AOP的声明式事务管理,以及两者如何在实际项目中集成使用。 **Hibernate编程式事务管理** Hibernate作为流行的ORM(对象关系映射)框架,提供了对JDBC事务的...