http://liusu.iteye.com/blog/380397

今天要用Hibernate做点实验,下载最新版得下来。解压,建项目,从tutorial copy代码。Tutorial里面提到说最新的Hibernate已经不需要用户自己使用ThreadLocal得方式来管理和持有session,而把这种session管理方式内置了,只要依据依据配置就可以用了

Java代码  
  1. hibernate.current_session_context_class = jta/thread/managed //Use thread
hibernate.current_session_context_class = jta/thread/managed //Use thread

HibernateUtil.java

Java代码  
  1. package org.hibernate.tutorial.util;
  2. import org.hibernate.SessionFactory;
  3. import org.hibernate.cfg.Configuration;
  4. public class HibernateUtil {
  5. private static final SessionFactory sessionFactory;
  6. static {
  7. try {
  8. // Create the SessionFactory from hibernate.cfg.xml
  9. sessionFactory = new Configuration().configure().buildSessionFactory();
  10. } catch (Throwable ex) {
  11. // Make sure you log the exception, as it might be swallowed
  12. System.err.println("Initial SessionFactory creation failed." + ex);
  13. throw new ExceptionInInitializerError(ex);
  14. }
  15. }
  16. public static SessionFactory getSessionFactory() {
  17. return sessionFactory;
  18. }
  19. }
package org.hibernate.tutorial.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}

在使用的时候大概都是如此调用:

Java代码  
  1. private Long createAndStoreEvent(String title, Date theDate) {
  2. Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  3. session.beginTransaction();
  4. Event theEvent = new Event();
  5. theEvent.setTitle(title);
  6. theEvent.setDate(theDate);
  7. session.save(theEvent);
  8. session.getTransaction().commit();
  9. return theEvent.getId();
  10. }
    private Long createAndStoreEvent(String title, Date theDate) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);
session.save(theEvent);
session.getTransaction().commit();
return theEvent.getId();
}

很顺利,跑起来也一切正常。 我有一个查询的需求。就是load一个Object对象需求。代码如下:

Java代码  
  1. private Event find(Event event) {
  2. Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  3. //session.beginTransaction();
  4. Event load = (Event) session.load(Event.class, event.getId());
  5. //session.getTransaction().commit();
  6. return load;
  7. }
 private Event find(Event event) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
//session.beginTransaction();
Event load = (Event) session.load(Event.class, event.getId());
//session.getTransaction().commit();
return load;
}

我一想,就是一普通的load和查询操作,应该不用开闭Transaction了。但是却报异常了:

Java代码  
  1. org.hibernate.HibernateException: get is not valid without active transaction
org.hibernate.HibernateException: get is not valid without active transaction

太抓狂了,就一些查询操作也要开闭Transaction。公司有使用过Hiberbate的小伙子说的记得应该是不用的。想想唯一的使用的区别就是得到Session的代码从

Java代码  
  1. HibernateUtil.getSessionFactory().openSession();
HibernateUtil.getSessionFactory().openSession();

变为了

Java代码  
  1. HibernateUtil.getSessionFactory().getCurrentSession();
HibernateUtil.getSessionFactory().getCurrentSession();

难道是这句HibernateUtil.getSessionFactory().getCurrentSession();有猫腻?
Checkout源码,跟进去看,果然:
HibernateUtil.getSessionFactory().getCurrentSession()将Session交给一个CurrentSessionContext来处理,根据配置,使用的是ThreadLocalSessionContext这个东东。查看他的源码:

Java代码  
  1. public final Session currentSession() throws HibernateException {
  2. Session current = existingSession( factory );
  3. if (current == null) {
  4. current = buildOrObtainSession();
  5. // register a cleanup synch
  6. current.getTransaction().registerSynchronization( buildCleanupSynch() );
  7. // wrap the session in the transaction-protection proxy
  8. if ( needsWrapping( current ) ) {
  9. current = wrap( current );//Warp Here????
  10. }
  11. // then bind it
  12. doBind( current, factory );
  13. }
  14. return current;
  15. }
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 );//Warp Here????
}
// then bind it
doBind( current, factory );
}
return current;
}

发现这里的Session已经是不纯洁了,已经成宋祖德嘴里的女明星了。被包了。看看被包的过程,

Java代码  
  1. protected Session wrap(Session session) {
  2. TransactionProtectionWrapper wrapper = new TransactionProtectionWrapper( session );
  3. Session wrapped = ( Session ) Proxy.newProxyInstance(
  4. Session.class.getClassLoader(),
  5. SESS_PROXY_INTERFACES,
  6. wrapper
  7. );
  8. // yick!  need this for proper serialization/deserialization handling...
  9. wrapper.setWrapped( wrapped );
  10. return wrapped;
  11. }
protected Session wrap(Session session) {
TransactionProtectionWrapper wrapper = new TransactionProtectionWrapper( session );
Session wrapped = ( Session ) Proxy.newProxyInstance(
Session.class.getClassLoader(),
SESS_PROXY_INTERFACES,
wrapper
);
// yick!  need this for proper serialization/deserialization handling...
wrapper.setWrapped( wrapped );
return wrapped;
}

被包的很过分,直接换成代理了,看看代理人的嘴脸,这个代理人是TransactionProtectionWrapper

看看他是用什么好东西包的:

Java代码  
  1. /**
  2. * {@inheritDoc}
  3. */
  4. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  5. try {
  6. // If close() is called, guarantee unbind()
  7. if ( "close".equals( method.getName()) ) {
  8. unbind( realSession.getSessionFactory() );
  9. }
  10. else if ( "toString".equals( method.getName() )
  11. || "equals".equals( method.getName() )
  12. || "hashCode".equals( method.getName() )
  13. || "getStatistics".equals( method.getName() )
  14. || "isOpen".equals( method.getName() ) ) {
  15. // allow these to go through the the real session no matter what
  16. }
  17. else if ( !realSession.isOpen() ) {
  18. // essentially, if the real session is closed allow any
  19. // method call to pass through since the real session
  20. // will complain by throwing an appropriate exception;
  21. // NOTE that allowing close() above has the same basic effect,
  22. //   but we capture that there simply to perform the unbind...
  23. }
  24. else if ( !realSession.getTransaction().isActive() ) {
  25. // limit the methods available if no transaction is active
  26. if ( "beginTransaction".equals( method.getName() )
  27. || "getTransaction".equals( method.getName() )
  28. || "isTransactionInProgress".equals( method.getName() )
  29. || "setFlushMode".equals( method.getName() )
  30. || "getSessionFactory".equals( method.getName() ) ) {
  31. log.trace( "allowing method [" + method.getName() + "] in non-transacted context" );
  32. }
  33. else if ( "reconnect".equals( method.getName() )
  34. || "disconnect".equals( method.getName() ) ) {
  35. // allow these (deprecated) methods to pass through
  36. }
  37. else {
  38. throw new HibernateException( method.getName() + " is not valid without active transaction" );
  39. }
  40. }
  41. log.trace( "allowing proxied method [" + method.getName() + "] to proceed to real session" );
  42. return method.invoke( realSession, args );
  43. }
  44. catch ( InvocationTargetException e ) {
  45. if ( e.getTargetException() instanceof RuntimeException ) {
  46. throw ( RuntimeException ) e.getTargetException();
  47. }
  48. else {
  49. throw e;
  50. }
  51. }
  52. }
/**
* {@inheritDoc}
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// If close() is called, guarantee unbind()
if ( "close".equals( method.getName()) ) {
unbind( realSession.getSessionFactory() );
}
else if ( "toString".equals( method.getName() )
|| "equals".equals( method.getName() )
|| "hashCode".equals( method.getName() )
|| "getStatistics".equals( method.getName() )
|| "isOpen".equals( method.getName() ) ) {
// allow these to go through the the real session no matter what
}
else if ( !realSession.isOpen() ) {
// essentially, if the real session is closed allow any
// method call to pass through since the real session
// will complain by throwing an appropriate exception;
// NOTE that allowing close() above has the same basic effect,
//   but we capture that there simply to perform the unbind...
}
else if ( !realSession.getTransaction().isActive() ) {
// limit the methods available if no transaction is active
if ( "beginTransaction".equals( method.getName() )
|| "getTransaction".equals( method.getName() )
|| "isTransactionInProgress".equals( method.getName() )
|| "setFlushMode".equals( method.getName() )
|| "getSessionFactory".equals( method.getName() ) ) {
log.trace( "allowing method [" + method.getName() + "] in non-transacted context" );
}
else if ( "reconnect".equals( method.getName() )
|| "disconnect".equals( method.getName() ) ) {
// allow these (deprecated) methods to pass through
}
else {
throw new HibernateException( method.getName() + " is not valid without active transaction" );
}
}
log.trace( "allowing proxied method [" + method.getName() + "] to proceed to real session" );
return method.invoke( realSession, args );
}
catch ( InvocationTargetException e ) {
if ( e.getTargetException() instanceof RuntimeException ) {
throw ( RuntimeException ) e.getTargetException();
}
else {
throw e;
}
}
}

呵呵,几乎所有正常的操作都必须在transcation.isActive()条件下才能执行。我要用的get,load,save, saveOrUpdate,list都在此列。

到此为止,算明白了。 寻到根了,Hibernate的理由是:

org.hibernate.context.ThreadLocalSessionContext

A CurrentSessionContext impl which scopes the notion of current session by the current thread of execution. Unlike the JTA counterpart, threads do not give us a nice hook to perform any type of cleanup making it questionable for this impl to actually generate Session instances. In the interest of usability, it was decided to have this default impl actually generate a session upon first request and then clean it up after the org.hibernate.Transaction associated with that session is committed/rolled-back. In order for ensuring that happens, the sessions generated here are unusable until after Session.beginTransaction() has been called. If close() is called on a session managed by this class, it will be automatically unbound.

Additionally, the static bind and unbind methods are provided to allow application code to explicitly control opening and closing of these sessions. This, with some from of interception, is the preferred approach. It also allows easy framework integration and one possible approach for implementing long-sessions.

The buildOrObtainSession, isAutoCloseEnabled, isAutoFlushEnabled, getConnectionReleaseMode, and buildCleanupSynch methods are all provided to allow easy subclassing (for long-running session scenarios, for example).

Author:

Steve Ebersole

用别人的东西得小心,知道他背后干了什么很重要啊。

==============

http://www.cnblogs.com/liuyang-1037/archive/2009/03/26/1422254.html

Configuration:

负责管理Hibernate的配置信息,这些配置信息都是从配置文件hibernate.cfg.xml或者Hibernate.properties读取的,当然也可以自定义文件名称,只要在实例化Configuration的时候指定具体的路径就可以了;

SessionFactiory:

Configuration的实例会根据当前的配置信息,构造SessionFactory实例。SessionFactory是线程安全的,一般情况下一个应用中一个数据库共享一个SessionFactory实例。

构建SessionFactory
Hibernate的SessionFactory接口提供Session类的实例,Session类用于完成对数据库的操作。由于SessionFactory实例是线程安全的(而Session实例不是线程安全的),所以每个操作都可以共用同一个SessionFactory来获取Session。

Hibernate配置文件分为两种格式,一种是xml格式的配置文件,另一种是Java属性文件格式的配置文件,因此构建SessionFactory也有两种方法,下面分别介绍。

2.6.1  从XML文件读取配置信息构建SessionFactory 从XML文件读取配置信息构建SessionFactory的具体步骤如下。

(1)创建一个Configuration对象,并通过该对象的configura()方法加载Hibernate配置文件,代码如下。

Configuration config = new Configuration().configure();

configura()方法:用于告诉Hibernate加载hibernate.cfg.xml文件。Configuration在实例化时默认加载classpath中的hibernate.cfg.xml,当然也可以加载名称不是hibernate.cfg.xml的配置文件,例如wghhibernate.cfg.xml,可以通过以下代码实现。

Configuration config = new Configuration().configure("wghhibernate.cfg.xml");

(2)完成配置文件和映射文件的加载后,将得到一个包括所有Hibernate运行期参数的Configuration实例,通过Configuration实例的buildSessionFactory()方法可以构建一个惟一的SessionFactory,代码如下。

SessionFactory sessionFactory = config.buildSessionFactory();

构建SessionFactory要放在静态代码块中,因为它只在该类被加载时执行一次。一个典型的构建SessionFactory的代码如下。

  1. import org.hibernate.*;
  2. import org.hibernate.cfg.*;
  3. public class CoreSession {
  4. static SessionFactory sessionFactory;
  5. //注意到这里的SessionFactory都是static的
  6. //初始化Hibernate,创建SessionFactory实例,只在该类被加载到内存时执行一次
  7. static{
  8. try{
  9. Configuration config = new Configuration().configure();
  10. sessionFactory = config.buildSessionFactory();
  11. } catch (Exception e) {
  12. System.out.println(e.getMessage());
  13. }
  14. }
  15. }

2.6.2  从Java属性文件读取配置信息构建SessionFactory
从Java属性文件读取配置信息构建SessionFactory的具体步骤如下。

(1)创建一个Configuration对象,此时Hibernate会默认加载classpath中的配置文件hibernate.properties,代码如下。

Configuration config = new Configuration();

(2)由于在配置文件中缺少相应的配置映射文件的信息,所以此处需要通过编码方式加载,这可以通过Configuration对象的

addClass()方法实现,具体代码如下。

config.addClass(BranchForm.class);

addClass()方法用于加载实体类。

(3)完成配置文件和映射文件的加载后,将得到一个包括所有Hibernate运行期参数的Configuration实例,通过Configuration实例

的buildSessionFactory()方法可以构建一个惟一的SessionFactory,代码如下。

SessionFactory sessionFactory = config.buildSessionFactory();

构建SessionFactory要放在静态代码块中,因为它只需在该类被加载时执行一次,一个典型的构建SessionFactory的代码如下。

  1. import org.hibernate.*;
  2. import org.hibernate.cfg.*;
  3. public class CoreSession {
  4. static SessionFactory sessionFactory;
  5. //初始化Hibernate,创建SessionFactory实例,只在该类被加载到内存时执行一次
  6. static{
  7. try{
  8. Configuration config = new Configuration();
  9. config.addClass(BranchForm.class);
  10. sessionFactory = config.buildSessionFactory();
  11. } catch (Exception e) {
  12. System.out.println(e.getMessage());
  13. }
  14. }
  15. }

Session:

一般的持久化方法(CRUD)都是通过Session来调用的,Session是非线程安全的。

Session的创建与关闭 :Session是一个轻量级对象,通常将每个Session实例和一个数据库事务绑定,也就是每执行一个数据库事务,都应该先创建一个新的Session实例,在使用Session后,还需要关闭Session。

Session的创建

创建SessionFactory后,就可以通过SessionFactory创建Session实例,通过SessionFactory创建Session实例的代码如下。

Session session=sessionFactory.openSession();

创建Session后,就可以通过创建的Session进行持久化操作了。

Session的关闭

在创建Session实例后,不论是否执行事务,最后都需要关闭Session实例,释放Session实例占用的资源。

关闭Session实例的代码如下:session.close();

新Hibernate SessionFactory().getCurrentSession()猫腻相关推荐

  1. Hibernate SessionFactory

    Hibernate SessionFactory Hibernate SessionFactory是我们通过它获取会话和执行数据库操作的工厂类. 目录[ 隐藏 ] 1 Hibernate Sessio ...

  2. SessionFactory.getCurrentSession与openSession的区别

    SessionFactory.getCurrentSession与openSession的区别 1. 如果使用的是getCurrentSession来创建session的话,在commit后,sess ...

  3. Sessionfactory.getCurrentSession与 openSession() 的区别

    1. getCurrentSession创建的session会和绑定到当前线程,而openSession不会. 2. getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而o ...

  4. spring boot: javax.persistence.PersistenceException: Unable to build Hibernate SessionFactory

    报错信息: Exception encountered during context initialization - cancelling refresh attempt: org.springfr ...

  5. Unable to build Hibernate SessionFactory

    ## 标题 **Unable to build Hibernate SessionFactory (郁闷啊!!!这个问题搞我好几天)** 使用struts+springData+Hibernate+j ...

  6. Hibernate - SessionFactory和Session详解

    [1]SessionFactory 接口 SessionFactory 接口是针对单个数据库映射关系经过编译后的内存镜像,是线程安全的. SessionFactory 对象一旦构造完毕,即被赋予特定的 ...

  7. Hibernate面试问题与解答

    Hibernate面试问题与解答 Hibernate是Java应用程序中使用最广泛的ORM工具之一.它在企业应用程序中用于数据库操作.所以我决定写一篇关于的帖子 hibernate面试问题,在面试前刷 ...

  8. hibernate面试问题_Hibernate面试问答

    hibernate面试问题 Hibernate is one of the most widely used ORM tool for Java applications. It's used a l ...

  9. Hibernate会话工厂

    Hibernate SessionFactory is the factory class through which we get sessions and perform database ope ...

最新文章

  1. vue实现多个元素或多个组件之间动画效果
  2. python 多维数组(array)排序
  3. 「Apollo」protobuf报错No module named ‘google‘
  4. 02/03_Pytorch安装、Conda安装Pythorch,换源、pytorch官网、验证、安装jupyter、卸载、安装、启动jupyter、配置Jupyter notebook、使用
  5. 2-01基本顺序表与元素外置顺序表recv
  6. 《构建之法》 读书笔记(3)
  7. 前端现在有发展前途吗?应届生好找工作吗?
  8. Drools只执行一个规则或者执行完当前规则之后不再执行其他规则(转)
  9. 最基本的01背包问题
  10. 《Python 学习手册4th》 第十六章 函数基础
  11. 在EWF上启用一个Hibernate Once/Resume Many环境
  12. 机器学习中分类和聚类的区别
  13. PLSQL Developer破解注册码
  14. 如何设计一个秒杀系统(完整版)
  15. 亚马逊AWS学习——EC2实例无法正确加载EBS卷问题的解决
  16. 约翰·亨尼斯(John Hennessy)—斯坦福大学-美国斯坦福大学校长介绍
  17. 下岗工冰城卖火“鱼豆腐”
  18. php pecl命令,linux 运行pecl命令报错解决办法
  19. 机器学习课堂笔记-作业二基本实现思路
  20. 利用DJi-mini2进行三维建模教程

热门文章

  1. 【数据结构与算法】之深入解析“等差数列划分”的求解思路与算法示例
  2. 2014\Province_C_C++_B\1 啤酒和饮料
  3. 1031:反向输出一个三位数
  4. ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车超声波避障实验(无舵机)
  5. Java中集合(一)Collection 、ListE 、ArrayListE
  6. java里的字符流_javaIO流中字符流的应用
  7. 从 Demo 中学习 Solidity
  8. on java8学习笔记2022.2.19-2022.2.20
  9. java(8)——和、|和||、!、^及三目运算符
  10. 深入理解C语言变量和内存——整理篇