Hibernate框架中Session和SessionFactory的作用学习

Session接口 
 

 Session接口对于Hibernate 开发人员来说是一个最重要的接口。然而在Hibernate中,实例化的Session是一个轻量级的类,创建和销毁它都不会占用很多资源。这在实际项目中确实很重要,因为在客户程序中,可能会不断地创建以及销毁Session对象,如果Session的开销太大,会给系统带来不良影响。但值得注意的是Session对象是并不一定是非线程安全的,因此在你的设计中,最好是一个线程只创建一个Session对象。 


  在Hibernate的设计者的头脑中,他们将session看作介于数据连接与事务管理一种中间接口。我们可以将session想象成一个持久对象的缓冲区,Hibernate能检测到这些持久对象的改变,并及时刷新数据库。我们有时也称Session是一个持久层管理器,因为它包含这一些持久层相关的操作,诸如存储持久对象至数据库,以及从数据库从获得它们。请注意,Hibernate 的session不同于JSP应用中的HttpSession。当我们使用session这个术语时,我们指的是Hibernate中的session,而我们以后会将HttpSesion对象称为用户session。 

Hibernate中session主要是用来操作数据库?

不用框架,纯java代码操作数据库用的是jdbc,代码量太多
    用hibernate则是简化了原先的jdbc操作数据库时——增删改查,需要写大量sql语句的弊端
    因此,hibernate就用session的一些方法来代替原先的增删改查操作:例如
    session.save();//保存
    session.get();//获取
    session.delete()//删除
    session.update();//修改等等


Hibernate 在操作数据库前需要得到Session的实例,这个类似于jdbc中的Connection。

获得Session的方法如下:

Session session = sessionFactory.openSession();


Hibernate  3中,取消了find()方法,必须通过Query或Criteria来进行查询。

对于session这个接口的学习可以说是最痛苦也是最复杂的,因为它所涉及的方面太多了,一些隐藏的机制也很多,谁让它是Central API呢。

对于它的几个最基本的方法如save()、delete()、flush()等的学习都花了我一定的时间。在深入了解这些这些方法前,了解session的缓存机制以及 Hibernate 中Java对象的状态对我们是很有帮助的。

一.Session的缓存

Java是纯面向对象的语言,因此不可能像C语言那样直接操纵内存,例如声明一段可用的内存空间。在Java里面,缓存通常是指Java对象的属性占用的内存空间,通常是一些集合类型的属性。在session接口的实现类SessionImpl中定义了一系列的Java集合,这些Java集合就构成了Session的缓存。

使用缓存的一个很明显的好处就是可以减少数据库访问的频率,提高应用程序的性能,因为从内存中读取数据显然要比从数据库中查询快多了。根据我个人的理解,Session的缓存实际上起到了一个“过渡仓库”作用。就像魔兽中的英雄一样,身上都会背有一个包,用来存放常用的物品如补血药水、补魔药水、回城卷等等。如果想用回城卷而身上没有回程卷的话就要跑到商店去shopping了,这样就会浪费大量的时间了,除非你此刻就在商店旁边;如果想用的回城卷的时候身上就有的话,英雄就可以直接用而不必大老远的跑到商店去了。我们的Session的缓存可以说就相当于英雄身上的背包,我的应用程序就是英雄,而数据库就是商店咯。

当然这个比喻不是很准确了,比方说在 Hibernate 应用中我们可以向数据库插入一条新的记录,而在魔兽中你是不可能给商店增加存货量的,只是为了便于理解,才作了这么一个对比。

二. Hibernate 中Java对象的状态

在一个 Hibernate 应用中,Java对象可以处于以下三个状态之一:

1.临时状态(Transient)。处于这个状态的对象还被没有纳入 Hibernate 的缓存管理体系,跟任何session都不关联,在数据库中也没有对应的记录。

2.持久化状态(Persistent)。处于这个状态的对象位于Session的缓存中,并且和数据库中的一条数据记录相对应。

3.游离状态(Detached)。处于这个状态的对象不再位于Session的缓存中,它与临时对象的最大区别在于,游离对象在数据库中还可能存在一条与它对应的记录。


游离状态的实例可以通过调用save()persist()或者saveOrUpdate()方法进行持久化。持久化实例可以通过调用 delete()变成游离状态。通过get()load()方法得到的实例都是持久化状态的。游离状态的实例可以通过调用 update()、0saveOrUpdate()lock()或者replicate()进行持久化。游离或者自由状态下的实例可以通过调用merge()方法成为一个新的持久化实例。

上述3个状态之间是可以相互转化的,而且我们所说的状态都是针对某一个session实例而言的,比方说,对象A对于session1而言是处于持久化状态的,因为它处于session1的缓存中,但是对于session2而言对象A并不在它的缓存中,因此它是处于游离状态的。

对于这几个状态的理解花费了我一定的时间,因为总是有一些稀奇古怪的念头在我脑海中产生。比如说,对于临时状态的定义,如果我新建一个对象,然后人为的让它属性的值和数据库中的一条记录对应,包括id的取值都一样。此时它能否说是处于游离状态呢?因为它和一条记录想对应呀。实际上这些情况都是由于一些不和规范的操作而产生的。在 Hibernate 应用中,无论Java对象处于临时状态、持久化状态还是游离状态,应用程序都不应该修改它的OID。OID的值应该由 Hibernate 来维护和负责,实际上 Hibernate 在同步缓存中的对象与数据库中的记录时,都是通过OID来进行关联和映射的,如果应用程序人为的修改了对象的OID,就会导致一些莫名其妙的错误,而且这样也不利于数据的同步。

  

     

  SessionFactory 接口 

  这里用到了一个设计模式――工厂模式,用户程序从工厂类SessionFactory中取得Session的实例。 Java JEE应用一般只有一个SessionFactory,


  SessionFactory并不是轻量级的!实际上它的设计者的意图是让它能在整个应用中共享,其创建和销毁需要耗费很大的资源。典型地来说,一个项目通常只需要一个SessionFactory就够了,但是当你的项目要操作多个数据库时,那你必须为每个数据库指定一个SessionFactory。 并且SessionFactory是线程安全,多个并发线程可以同时访问一个 SessionFactory 并从中获取Session实例。比如服务于客户请求的各线程都通过这个工厂来获得Hibernate的Session实例,这 也是为什么SessionFactory接口的实现必须是线程安全的原因。还有,SessionFactory的内部状态包含着同对象关系影射有关的所有元数据,它是 不可变的,一旦创建好后就不能对其进行修改了。 

SessionFactory在Hibernate中实际起到了一个缓冲区的作用,它缓冲了Hibernate自动生成的SQL语句和一些其它的映射数据,还缓冲了一些将来有可能重复利用的数据。 

SessionFactory接口提供了获取session类实例的方法。

一般有两种方法创建session实例:

1、getCurrentSession方法:

采用该方法创建的session实例会绑定到当前线程当中。且session实例会在提交或回滚时自动关闭。

2、openSession方法:

采用该方法会创建新的的session实例。使用完后需进行手动关闭。

   为了能创建一个SessionFactory对象 应该在Hibernate初始化的时候创建一个Configuration类的实例 并将已经写好的映射文件交给他处理 这样Configuration对象就可以创建一个SessionFactory对象 当SessionFactory对象创建成功后 Configuration对象就没用用了 就可以简单的抛弃他
示例代码:
  1. Configuration cfg = new Configuration();
  2. cfg.addResource("com/demo/hibernate/beans/User.hbm.xml");
  3. cfg.setProperty(System.getProperties());
  4. SessionFactory sessionFactory = cfg.buildSessionFactory();

再说下,SessionFactory用到了一个设计模式 工厂模式 用户程序从工程类SessionFactory取得Session实例 设计者的意图就是让它能在整个应用中共享 典型的来说 一个项目通常只需要一个SessionFactory就够了 因此我们就设计了HibernateSessionFactory.java这个辅助类 定义了一个静态的Configuration和SessionFactory对象

 

  1. private static final Configuration cfg = new Configuration();
  2. private static org.hibernate.SessionFactory sessionFactory;

这两个对象对整个应用来说只有一个实例存在 因此为用户的访问定义一个本地线程变量:

 

  1. private static final ThreadLocal threadLocal = new ThreadLocal();

 

该线程变量是静态的 对每一个访问该线程的用户产生一个实例 这样在要取得Session对象时 首先从当前用户的线程中取得Session对象 如果还没有创建 则从SessionFactory中创建一个Session 此时会判断SessionFactory对象是否已经创建 该对象对这个应用来说 只有一个 因此 只有第一次访问该变量的用户才会创建该对象

HibernateSessionFactory.java 取得Session对象的过程如下表示

 

  1. public static Session currentSession() throws HibernateException {
  2.         Session session = (Session) threadLocal.get();

  3.         if (session == null) {
  4.             if (sessionFactory == null) {
  5.                 try {
  6.                     cfg.configure(CONFIG_FILE_LOCATION);
  7.                     sessionFactory = cfg.buildSessionFactory();
  8.                 }
  9.                 catch (Exception e) {
  10.                     System.err.println("%%%% Error Creating SessionFactory %%%%");
  11.                     e.printStackTrace();
  12.                 }
  13.             }
  14.             session = sessionFactory.openSession();
  15.             threadLocal.set(session);
  16.         }

  17.         return session;
  18.     }

首先判断threadLocal中是否存在Session对象 如果不存在 则创建Session对象 在创建Session对象时 首先要判断系统是否已经加载Configuration 如果没有sessionFactory 则需要先创建该对象 创建完成的Session对象 需要保存在threadLocal中以供本次访问线程的下一次调用

在关闭Session对象是 只需要从当前线程中取得Session对象 关闭该对象 并置空本地线程变量即可

 

  1. public static void closeSession() throws HibernateException {
  2.         Session session = (Session) threadLocal.get();
  3.         threadLocal.set(null);

  4.         if (session != null) {
  5.             session.close();
  6.         }
  7.     }

最后说一下用hibernate的三个必须要了解的三个方面(具体代码我就不写了,你去hibernate框架提供的例子里面找,hibernate有中文文档提供给你的)
1。主配置文件:hibernate.cfg.xml:
     用来 配置数据库连接;
          映射文件的配置;
          其他一些配置;
2。映射文件:XXX.hbm.xml     //XXX代表你要关联的类的名称是是什么,你就写什么
     向数据中存储数据需要用对象来存储封装,那数据库怎样将对象的属性跟数据库中表的属性对应,就需要你写映射文件;(这是学习重点,量比较多)
3。api:也就是你上面问的session的用法等等
     这部分只要了解一些简单操作就行,往往得到session后代码就一句话,这块比较简单,重点还是映射文件那块,只要配置文件整出来,这块不成问题。

你可能感兴趣的:(Java)