Hibernate有很多值得学习的地方,这里我们主要介绍Hibernate ThreadLocal,包括介绍Hibernate官方开发手册标准示例等方面。
Hibernate ThreadLocal
它会为每个线程维护一个私有的变量空间。实际上, 其实现原理是在JVM 中维护一个Map,这个Map的key 就是当前的线程对象,而value则是 线程通过Hibernate ThreadLocal.set方法保存的对象实例。当线程调用Hibernate ThreadLocal.get方法时, Hibernate ThreadLocal会根据当前线程对象的引用,取出Map中对应的对象返回。
这样,Hibernate ThreadLocal通过以各个线程对象的引用作为区分,从而将不同线程的变量隔离开来。
Hibernate官方开发手册标准示例:
public class HibernateUtil { private static SessionFactory sessionFactory; static { try { // Create the SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (HibernateException ex) { throw new RuntimeException( "Configuration problem: " + ex.getMessage(), ex ); } } public static final ThreadLocal session = new ThreadLocal(); public static Session currentSession() throws HibernateException { Session s = (Session) session.get(); // Open a new Session, if this Thread has none yet if (s == null) { s = sessionFactory.openSession(); session.set(s); } return s; } public static void closeSession() throws HibernateException { Session s = (Session) session.get(); session.set(null); if (s != null) s.close(); } } 通过filter实现session的重用:
public class PersistenceFilter implements Filter {
protected static ThreadLocal hibernateHolder = new ThreadLocal();
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException,ServletException {
hibernateHolder.set(getSession());
try {
……
chain.doFilter(request, response);
……
}
finally {
Session sess = (Session)hibernateHolder.get();
if (sess != null) { hibernateHolder.set(null);
try { sess.close(); } catch (HibernateException ex) {
throw new ServletException(ex);
}
}
}
}
……
}
最近对Hibernate的ThreadLocal Session模式有点兴趣。于是根据曹晓钢翻译的Hibernate Reference做了个小测验,结果发现了一个小bug。 代码很简单,都是利用Hibernate Reference中现成的代码。 首先是一个辅助的得到线程安全的session的HibernateUtil类, public class HibernateUtil { public static final SessionFactory sessionFactory; static{ try { sessionFactory = new Configuration().configure().buildSessionFactory(); } catch(Throwable ex){ throw new ExceptionInInitializerError(ex); } } public static final ThreadLocal session = new ThreadLocal(); public static Session currentSession() { Session s = (Session) session.get(); if (s==null ) { s = sessionFactory.getCurrentSession(); session.set(s); } return s; } public static void closeSession() { Session s = (Session) session.get(); if (s!=null) s.close(); session.set(null); } public static SessionFactory getSessionFactory() { return sessionFactory; } } 然后是一个测试插入数据的代码。也很简单,也是仿Hibernate Reference上面的代码。 public class InsertUser { public static void main(String[] args) { Session session = HibernateUtil.currentSession(); Transaction tx= session.beginTransaction(); TUser user = new TUser(); user.setName("Emma"); session.save(user); tx.commit(); HibernateUtil.closeSession(); } } 就这么简单一个程序,运行到最后,出现一个错误。 org.hibernate.SessionException: Session was already closed at org.hibernate.impl.SessionImpl.close(SessionImpl.java:270) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301) at $Proxy0.close(Unknown Source) at Util.HibernateUtil.closeSession(HibernateUtil.java:36) at test.InsertUser.main(InsertUser.java:20) Exception in thread "main" 错误出现在 HibernateUtil.closeSession(); 这一行,意思是session已经关闭了,再次关闭它就引起异常了。 不过前面的代码中只有个tx.commit(); 提交事务 而已,并没有自动关闭session啊? 于是把DEBUG信息调用出来,发现了以下几句提示: DEBUG [main] - after transaction completion DEBUG [main] - automatically closing session DEBUG [main] - closing session DEBUG [main] - connection already null in cleanup : no action DEBUG [main] - allowing proxied method [close] to proceed to real session DEBUG [main] - closing session org.hibernate.SessionException: Session was already closed 特别是下面这3句话引起了我的注意,果然是session关闭了,而且是在 事务结束以后自动关闭的。 DEBUG [main] - after transaction completion DEBUG [main] - automatically closing session DEBUG [main] - closing session 那么这个机制是怎么发生的呢? 打开了Hibernate3的源码,我找到了答案。 首先,根据sessionFactory = new Configuration().configure().buildSessionFactory(); 打开Configuration类的buildSessionFactory()方法,找到sessionFactory的生成语句 return new SessionFactoryImpl( this, mapping, settings, getInitializedEventListeners() ); ,然后找到SessionFactoryImpl的getCurrentSession方法,发现是这么定义的。 public org.hibernate.classic.Session getCurrentSession() throws HibernateException { if ( currentSessionContext == null ) { throw new HibernateException( "No CurrentSessionContext configured!" ); } return currentSessionContext.currentSession(); } 他调用的是一个currentSessionContext的currentSession方法。查找currentSessionContext变量, currentSessionContext = buildCurrentSessionContext(); ,知道了buildCurrentSessionContext方法产生了这个currentSessionContext 对象。 private CurrentSessionContext buildCurrentSessionContext() { String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS ); // for backward-compatability if ( impl == null && transactionManager != null ) { impl = "jta"; } if ( impl == null ) { return null; } else if ( "jta".equals( impl ) ) { return new JTASessionContext( this ); } else if ( "thread".equals( impl ) ) { return new ThreadLocalSessionContext( this ); } else { try { Class implClass = ReflectHelper.classForName( impl ); return ( CurrentSessionContext ) implClass .getConstructor( new Class[] { SessionFactoryImplementor.class } ) .newInstance( new Object[] { this } ); } catch( Throwable t ) { log.error( "Unable to construct current session context [" + impl + "]", t ); return null; } } } 这个方法就是用来判断使用JTA管理这个SessionContext还是用ThreadLocal来管理SessionContext的。 在我们这里是用 ThreadLocal 来管理的,于是找到了currentSessionContext 的实现类是 ThreadLocalSessionContext。 找到该类的currentSession方法 public final Session currentSession() throws HibernateException { Session current = existingSession( factory ); if (current == null) { current = buildOrObtainSession(); // register a cleanup synch current.getTransaction().registerSynchronization( buildCleanupSynch() ); // wrap the session in the transaction-protection proxy if ( needsWrapping( current ) ) { current = wrap( current ); } // then bind it doBind( current, factory ); } return current; } 然后跟踪到 buildOrObtainSession(),就是这里,打开了session。 protected Session buildOrObtainSession() { return factory.openSession( null, isAutoFlushEnabled(), isAutoCloseEnabled(), getConnectionReleaseMode() ); } 注意第三个参数:isAutoCloseEnabled 打开Session这个接口,看到 openSession方法中这个参数是如下描述的: * @param autoCloseSessionEnabled Should the session be auto-closed after * transaction completion? ,就是说session是否应该在事务提交后自动关闭。 然后打开 ThreadLocalSessionContext 的isAutoCloseEnabled()方法。 /** * Mainly for subclass usage. This impl always returns true. * * @return Whether or not the the session should be closed by transaction completion. */ protected boolean isAutoCloseEnabled() { return true; } 看到如下提示:Whether or not the the session should be closed by transaction completion ,即无论如何session应该在事务完成后关闭。 答案就在这里,就是说在ThreadLocal Session模式下面,只要提交了事务,那么session就自动关闭了,因此我参照Hibernate Refernece上面的代码写的在事务关闭以后再调用HibernateUtil.closeSession();是不对的,这句代码是完全多余的。
分享到:
相关推荐
例如,Spring 中的 TransactionTemplate 和 AOP 模块利用 `ThreadLocal` 存储当前事务信息,Hibernate 中的 Session 管理也依赖于 `ThreadLocal` 来保持线程绑定的 Session。 7. **线程安全** - `ThreadLocal` ...
### 二、ThreadLocal API详解 1. `ThreadLocal()`:创建一个新的线程局部变量。 2. `T get()`:返回当前线程的ThreadLocal变量副本中的值,如果这是线程第一次调用get(),则初始化副本。 3. `protected T initial...
例如,在 HibernateUtil 类中,我们可以定义一个 ThreadLocal 变量来保存 Hibernate 的 Session。 ```java public class HibernateUtil { private static Log log = LogFactory.getLog(HibernateUtil.class); ...
#### 二、配置步骤详解 ##### 1. 导入必要的库文件 在开始配置之前,首先需要确保项目中已经包含了Hibernate所需的库文件以及进行数据库连接所需的驱动程序。这通常包括以下几个库: - `hibernate-core.jar`:...
### Hibernate开发必备版知识点解析 #### 一、Hibernate概述 Hibernate是一种开源的对象关系映射(Object Relational Mapping,ORM)框架,它为Java应用程序提供了一种简单的方式来与关系型数据库进行交互。通过...
### 知识点详解:Java.lang.ThreadLocal 类 #### 一、概述 **ThreadLocal** 并非线程的一种特殊实现形式,而是一种为每个线程提供独立副本的机制,通常被称为“线程局部变量”。这种机制使得每个线程都可以独立...
### Hibernate 3.2 学习笔记:一对一主键关联详解 #### 一、一对一主键关联概述 在本节中,我们将详细探讨 Hibernate 3.2 中的一对一关联关系,尤其是通过主键实现的双向关联。这种关联通常出现在需要紧密绑定两个...
### Hibernate业务层控制详解 #### 一、引言 Hibernate是一个强大的对象关系映射(ORM)框架,它简化了Java应用程序与数据库之间的交互过程。在实际应用开发中,如何有效地控制事务是确保数据一致性和系统稳定性的...
【Hibernate3实战 MyEclipse】教程详解 在Java开发领域,Hibernate3是一个强大的ORM(对象关系映射)框架,它极大地简化了数据库操作,使得开发者能够以面向对象的方式处理数据库事务。MyEclipse作为一款集成开发...
- **元素详解**:包括`<class>`、`<id>`、`<property>`等元素的使用方法。 **1.1.4 Hibernate配置** - **`hibernate.cfg.xml`配置**:详细介绍如何配置Hibernate的核心配置文件,包括数据库连接信息、映射文件路径...
**Hibernate框架详解** Hibernate是Java世界中的主流ORM框架,它提供了对象与数据库表之间的映射,简化了数据访问。关键概念包括: 1. **实体类(Entity)**:代表数据库中的表,通过@Entity注解标识。 2. **持久...
#### 三、Struts+Spring+Hibernate整合开发详解 ##### 1. 整合背景 随着企业应用复杂度的增加,单一框架已经难以满足需求。为了提高系统的灵活性、可扩展性和可维护性,开发者通常会采用多种框架进行整合。Struts...
### SSH面试题详解 #### 一、Struts的Action线程安全性 **问题:** Struts的Action是否线程安全?如果不是,如何确保Action的线程安全? - **Struts 1**: 非线程安全。Struts 1中Action采用的是单例模式,即整个...
这里使用了 `ThreadLocal` 来存储当前线程所关联的数据源。`HandleDataSource` 类中的 `putDataSource()` 和 `getDataSource()` 方法分别用于设置和获取当前线程的数据源。 4. **数据源切面类**: 定义一个切面类 ...
### Java面试题全集知识点详解 #### 一、对象关系映射(ORM) **知识点概述:** 对象关系映射(Object-Relational Mapping,简称ORM)是一种编程技术,用于解决面向对象模型与关系型数据库之间的差异。ORM允许开发...
### Java框架面试题详解 #### 一、对象关系映射(ORM)技术 **1. 什么是ORM?** 对象关系映射(Object-Relational Mapping,简称ORM)是一种编程技术,用于解决面向对象编程语言与关系型数据库之间的不兼容性问题。...
以下是部分面试题的详解: 1. **Java的优势**: Java的主要优势包括跨平台性、面向对象、自动内存管理(垃圾回收)、丰富的类库、稳定性和安全性等。面试者应能阐述这些特点如何在实际项目中发挥作用。 2. **单例...
**MVC(Model-View-Controller)架构模式详解** MVC是一种广泛应用于Web开发的软件设计模式,它的核心思想是将应用程序的业务逻辑、用户界面和数据访问分离开来,以提高代码的可维护性和可扩展性。在MVC模式中,...