12.0 管理Session和批量操作

管理Session

一.Hibernate自身提供了三种管理Session对象的方法: 

  • Session对象的生命周期与本地线程绑定 
  • Session对象的生命周期与JTA事务绑定 
  • Hibernate委托程序管理Session对象的生命周期 

二.在Hibernate的配置文件中,hibernate.current_session_context_class属性用于指定Session管理方式,可选值包括: 
  • thread: Session对象的生命周期与本地线程绑定 
  • jta*: Session对象的生命周期与JTA事务绑定 
  • managed: Hibernate委托程序来管理Session对象的生命周期 
      
三.Hibernate按以下规则把Session与本地线程绑定: 
  当一个线程(threadA)第一次调用SessionFactory的 getCurrentSession() 方法时,该方法会创建一个新的Session(sessionA)对象,把该对象与threadA绑定,并将sessionA返回。 
  当threadA再次调用SessionFactory对象的getCurrentSession()方法时,该方法将返回sessionA对象。 
  当threadA提交sessionA对象关联的事务时,Hibernate会自动flush sessionA对象的缓存,然后提交事务, 关闭sessionA对象 。当threadA撤销sessionA关联的事务时, 也会自动关闭sessionA对象 。 
  若threadA再次调用SessionFactory对象的getCurrentSession()方法时,该方法 会创建一个新的Session(sessionB)对象 ,把该对象与threadA绑定,并将sessionB返回。

四.现在介绍第一种管理方式,即将Session对象的生命周期与本地线程绑定。 
  如果把Hibernate配置文件的hibernate.current_session_context_class属性设置为thread,Hibernate就会按照与本地线程绑定的方式来管理Session。 

①. 在Hibernate 的配置文件hibernate.cfg.xml 中配置 hibernate.current_session_context_class

<!-- 配置管理session 的方式 -->  
    <property name="hibernate.current_session_context_class">thread</property>  

②. 创建管理session 的类HibernateUtils.java

import org.hibernate.Session;  
import org.hibernate.SessionFactory;  
import org.hibernate.cfg.Configuration;  
import org.hibernate.service.ServiceRegistry;  
import org.hibernate.service.ServiceRegistryBuilder;  
  
public  class HibernateUtils {  
      
    //hIbernate的构造器  
    public HibernateUtils(){}  
      
    //获取Hibernte的单实例  
    private static HibernateUtils instance =  new HibernateUtils();  
    public static HibernateUtils getInstance(){  
        return instance;  
    }  
      
    //获取sessionFactory  
    private SessionFactory sessionFactory;  
    public SessionFactory getSessionFaction(){  
        if(sessionFactory == null){  
            Configuration configuration = new Configuration().configure();  
              
            ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()  
                                            .applySettings(configuration.getProperties())  
                                            .buildServiceRegistry();  
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);  
        }  
        return sessionFactory;  
    }  
      
    // 通过getCurrentSession() 可以把 session和 当前线程绑定  :Current 的意思是:当前的  
    public Session getSession(){  
        return getSessionFaction().getCurrentSession();  
    }  
}  
Department.java

public class DepartmentDao{
	//内部获取Session
	//获取和当前线程绑定的Session对象
	//1.不需要从外部传入Sesssion对象
	//2.多个DAO方法也可以使用一个事务
	Session session=HibernateUtils.getInstance().getSession();
	System.out.println(Session.hashCode());
	
	session.save(dept);
}

测试:

@Test  
public void testHibernateManageSession(){  
    //获取session  
    //开启事务  
    Session session = HibernateUtils.getInstance().getSession();  
    System.out.println("-->" + session.hashCode());  
    Transaction transaction = session.beginTransaction();  
      
    DepartmentDAO departmentDAO = new DepartmentDAO();  
      
    Department dept = new Department();  
      
    dept.setName("ChuckHero");  
      
    departmentDAO.save(dept);  
    departmentDAO.save(dept);  
    departmentDAO.save(dept);  
  
    //若 Session 是由 thread 来管理的,则 在提交或回滚事务后,就 已经关闭Session  
    System.out.println( "session.isOpen()1: " + session.isOpen());  
    transaction.commit();  
    System.out.println( "session.isOpen()2: " + session.isOpen());  
}  

打印结果:观察它们的hashCode 的值和提交事务前后session.isOpen的值:

-->852989707  
session.hashCode: 852989707  
Hibernate:   
    select  
        user_deptid.nextval   
    from  
        dual  
session.hashCode: 852989707  
session.hashCode: 852989707  
session.isOpen()1: true  
Hibernate:   
    insert   
    into  
        BB_DEPARTMENTS  
        (NAME, ID)   
    values  
        (?, ?)  
session.isOpen()2: false  


批量操作

批量处理数据是指在一个事务中处理大量数据。 
  在应用层进行批量操作,主要有以下方式: 
  1.通过Session 
  2.通过HQL 
  3.通过StatelessSession 
  
4.通过JDBC API(推荐方式,效率最高) 
   
通过Session进行批量操作: 
  Session的save()及update()方法都会把处理的对象存放在自己的缓存中。如果通过一个Session对象来处理大量持久化对象,应该及时从缓存中清空已经处理完毕并且不会再访问的对象。具体的做法是在处理完一个对象或小批量对象后,立即调用flush()方法刷新缓存,然后再调用clear()方法情况缓存。 
  通过Session来进行处理操作会受到以下约束: 
  1.需要在Hibernate配置文件中设置JDBC单次批量处理的数目,应保证每次向数据库发送的批量的SQL语句数目与batch size属性一致。 
  2.若对象采用”identity”标识生成器,则Hibernate无法在JDBC曾进行批量插入操作 
  3.进行批量操作时,建议关闭Hibernate的二级缓存

下面的代码演示了通过session批量插入数据:

News news = null;
 for(int i = 0; i < 10000; i++) {
     news = new News();
     news.setTitle("--" + i);

    session.save(news);
     if((i + 1) % 20 == 0) {
         session.flush();
         session.clear();
     }
 }

      对于批量更新,在进行批量更新时,如果一下子把所有对象都加载到Session缓存,然后在缓存中一一更新,显然是不可取的。 
  使用可滚动的结果集org.hibernate.ScrollableResults,该对象中实际上并不包含任何对象,只包含用于在线定位记录的游标。只有当程序遍历访问ScrollableResults对象的特定元素时,它才会到数据库中加载相应的对象。 
  org.hibernate.ScrollableResults对象由Query的scroll方法返回。 
  代码如下:
ScrollableResults sr = session.createQuery("FROM News").scroll();

        int count = 0;
        while (sr.next()) {
            News n = (News) sr.get(0);
            n.setTitle(n.getTitle() + "*****");

            if (((count++) + 1) % 100 == 0) {
                session.flush();
                session.clear();
            }
        }

通过HQL进行批量操作:

注意:HQL只支持INSERT INTO … SELECT形式的插入语句,但不支持INSERT INTO … VALUES形式的插入语句,所以使用HQL不能进行批量插入操作。

通过StatelessSession进行批量操作:

从形式上看,StatelessSession与Session的用法类似。StatelessSession与Session相比,有以下区别: 
  StatelessSession没有缓存,通过StatelessSession来加载、保存或更新后的对象处于游离状态. 
  StatelessSession不会与Hibernate的二级缓存交互。 
  当调用StatelessSession的save()、update()或delete()方法时,这些方法会立即执行相应的SQL语句,而不会仅计划执行一条SQL语句。 
  StatelessSession不会进行脏检查,因此修改了Customer对象属性后,还需要调用StatelessSession的update()方法来更新数据库中数据。 
  StatelessSession不会对关联的对象进行任何的级联操作。 
  通过同一个StatelessSession对象两次加载的OID为1的Customer对象,得到的两个对象内存地址不同。 
  StatelessSession所做的操作可以被Interceptor拦截器捕获到,但是会被Hibernate的事件处理系统忽略掉。 
   
通过JDBC API执行批量操作:(推荐) 
  这是效率最高的方法,代码如下:

    public void testBatch() {
        session.doWork(new Work() {
            @Override
            public void execute(Connection connection) throws SQLException {
                // 通过 JDBC 原生的 API 进行操作, 效率最高, 速度最快!
            }
        });
    }


参考:http://blog.csdn.net/xiangwanpeng/article/details/53517051

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值