openSession与getCurrentSession

本文探讨了Hibernate中的openSession和getCurrentSession两个方法。openSession每次调用都会创建新session,而getCurrentSession则获取或创建当前线程的session,并在同一个事务中使用。在SSH框架中,通常推荐使用getCurrentSession,因为它自动处理事务,无需手动关闭session。配置getCurrentSession需设置current_session_context_class属性,如设为thread,适用于单数据库连接管理事务。但在Spring事务管理中,必须正确配置SessionFactory并使用getCurrentSession处在事务环境中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在比较openSession和getCurrentSession这两个方法之前,我们先认识一下这两个方法。

在进行配置信息管理时,我们一般进行一下简单步骤:

Configuration cfg = new Configuration(); // 获得配置信息对象
SessionFactory sf = cfg.configure().buildSessionFactory(); //解析并建立Session工厂

1. Session session = sf.getCurrentSession(); // 获得Session
2. Session session = sf.openSession(); // 打开Session

对于上述的两个方法,有以下区别:

  1. openSession 从字面上可以看得出来,是打开一个新的session对象,而且每次使用都是打开一个新的session,假如连续使用多次,则获得的session不是同一个对象,并且使用完需要调用close方法关闭session。

  2. getCurrentSession ,从字面上可以看得出来,是获取当前上下文一个session对象,当第一次使用此方法时,会自动产生一个session对象,并且连续使用多次时,得到的session都是同一个对象,这就是与openSession的区别之一,简单而言,getCurrentSession 就是:如果有已经使用的,用旧的,如果没有,建新的。

注意:在实际开发中,往往使用getCurrentSession多,因为一般是处理同一个事务(即是使用一个数据库的情况),所以在一般情况下比较少使用openSession或者说openSession是比较老旧的一套接口了;

对于getCurrentSession 来说,有以下一些特点:

1.用途,界定事务边界

2.事务提交会自动close,不需要像openSession一样自己调用close方法关闭session

3.上下文配置(即在hibernate.cfg.xml)中,需要配置:

<property name="current_session_context_class">thread</property>

需要注意,这里的current_session_context_class属性有几个属性值:jta、thread 常用 , custom、managed 少用

a).thread使用connection 单数据库连接管理事务

b).jta (Java transaction api) Java 分布式事务管理 (多数据库访问),jta 由中间件提供(JBoss WebLogic 等, 但是tomcat 不支持)

下面是openSession 和 getCurrentSession 简单实例的区别 :

1.openSession方式 :

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.hibernate.model.Student; // 注意包路径

public class StudentTest {
    public static void main(String[] args) {

        Student s = new Student();
        s.setId(1);
        s.setName("s1");
        s.setAge(1);

        Configuration cfg = new Configuration(); // 获得配置信息对象
        SessionFactory sf = cfg.configure().buildSessionFactory(); //解析并建立Session工厂
        Session session = sessionFactory.openSession(); // 打开Session

        session.beginTransaction(); // 看成一个事务,进行操作
        session.save(s); // 会找到 Student 这个类,寻找set方法
        session.getTransaction().commit(); // 提交对数据的操作

        session.close();

        sf.close();
    }
}

2.getCurrentSession方式 :

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.hibernate.model.Student; // 注意包路径

public class StudentTest {
    public static void main(String[] args) {

        Student s = new Student();
        s.setId(1);
        s.setName("s1");
        s.setAge(1);

        Configuration cfg = new Configuration(); // 获得配置信息对象
        SessionFactory sf = cfg.configure().buildSessionFactory(); //解析并建立Session工厂
        Session session = sessionFactory.getCurrentSession(); // 打开Session

        session.beginTransaction(); // 看成一个事务,进行操作
        session.save(s); // 会找到 Student 这个类,寻找set方法
        session.getTransaction().commit(); // 提交对数据的操作

        sf.close();
    }
}

SSH中使用getCurrentSession()获得session

在hibernate的配置文件中增加属性:

<property name="current_session_context_class">thread</property>

如下代码 :

<hibernate-configuration>    
    <session-factory>   
        <property name="connection.url">jdbc:mysql://localhost:3306/dbtest</property>  
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>  
        <property name="myeclipse.connection.profile">dbtest</property>  
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>  
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="show_sql">true</property>  
        <property name="current_session_context_class">thread</property>  

        <mapping resource="com/pc386/hibernate/entity/User.hbm.xml" />  

    </session-factory>    
</hibernate-configuration>  

在SSH中,如果把hibernate交给Spring的管理事物中,那么应该修改Spring的配置文件applicationContext.xml文件的属性,在sessionFactory的属性中增加: <prop key="current_session_context_class">thread</prop>

代码如下:

<bean id="sessionFactory"                                   
                class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
      <property name="dataSource">  
          <ref local="dataSource"/>  
      </property>  

      <property name="mappingResources">  
          <list>  
              <value>User.hbm.xml </value>  
          </list>
      </property>  

      <property name="hibernateProperties">  
          <props>  
              <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
              <!--               
              <prop key="hibernate.transaction.factory_class">
                                  org.hibernate.transaction.JDBCTransactionFactory</prop>  
              -->  
              <prop key="hibernate.current_session_context_class">thread</prop>        
          </props>   
      </property>  
</bean>  

原文出处
http://blog.youkuaiyun.com/daryl715/archive/2007/02/11/1507385.aspx

Java代码 收藏代码
以前单独用Hibernate2.0的时候,为了保证一个线程中每次取出的session都是一个对象,就使用官方提供的一个HibernateUtils,将第一次取出的session放入ThreadLocal中,以后每次从这里面取出的session都是一个对象,可以保证事务的正常执行。

后来升级到3.0,也这样延用下去,没怎么关心3.0的新特性。

前几天想将Hibernate加入到SPRING的事务管理中,但是我又不想使用spring提供的HibernateDaoSupport或HibernateTemplate,只想像以前那样在一个线程中的任意地方都能得到同一个session。这样就出问题了,spring管理事务的话,如果要保证当前线程内只有一个session,需要将sessionFactory传递给org.springframework.orm.hibernate3.HibernateTransactionManager,spring负责事务的开始,提交,回滚以及session的关闭,假设spring用于管理事务的session是(session1)。如果我还用HibernateUtils.getCurrentSession()方法获得session的话,得到的session却是(session2),和开始事务的session不是同一个对象,就造成session2的事务没有提交,对数据库的操作无效。

后来搜索到原来Hibernate3.0以后,sessionFactory多了个新的方法getCurrentSession()。我心里很高兴,这样不就解决我的问题了吗?

于是我就将HibernateUtils中的session=sessionFactory.openSession()方法改为了session=sessionFactory.getCurrentSession().

运行测试竟然错了,

提示什么TransactionManager出错了,上网上搜了搜,原来使用getCurrent方法必须配置事务管理,需要和jta或thread绑定。我不想用jta,当然要和线程绑定了。我在hibernate的配置文件中加入了thread,又运行,还是出同样的错误。继续上网上查资料,基本没有相关资料。后来费了好大劲才发现,原来在hibernate3.0里只能和jta绑定,我copy了新的3.2的包,这下可以了。不出那个事务管理的错了,变成了org.hibernate.HibernateException: save is not valid without active transaction错误。继续搜,只有一个相关资料,说使用getCurrentSession()方法必须在事务中运行。不管查询还是更新操作都要开始事务,操作,提交事务才行。

可是我已经配置了让spring管理事务,为什么出这个错误?看来只有一个原因,spring在通过sessionFactory获取session时,没有调用getCurrentSession()方法。

自己手动加入事务的开始,提交,成功了。

经过多次实验,发现,只能能spring中配置sessionFactory,才能让spring管理hibernate的事务。

<bean id="sessionFactory"       
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
    <property name="dataSource">  
        <ref local="dataSource"/>  
    </property>  

    <property name="mappingResources">  
        <list>  
            <value>User.hbm.xml </value>  
        </list>  
    </property>  

    <property name="hibernateProperties">  
        <props>  
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>  
            <!--  
            <prop key="hibernate.transaction.factory_class">
                            org.hibernate.transaction.JDBCTransactionFactory</prop>  
            -->  
            <prop key="hibernate.current_session_context_class">thread</prop>
        </props>  
    </property>  
</bean>  

在程序中要用到session的时候,过程如下:

UserDAOImpl:  

{  

    SessionFactory sf = [从spring中得到sessionFactory];  

    Session session = sf.getCurrentSession();  

    //数据库操作  

}  

这么乱。写一下总结。

  1. 如果想让spring帮你管理事务,只能在spring中配置SessionFactory。如果使用hibernate原有的sessionFactory,则只能自己手动管理事务。

  2. 如果想使用sessionFactory.getCurrentSession()方法,必须配置sessionFactory和jta或thread绑定。但是hibernate3.0不支持与thread绑定,3.1以上才支持。

  3. sessionFactory.getCurrentSession()方法取得的session,在做数据库操作时必须在事务中做,包括只读的查询,否则会报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值