Hibernate学习之批量处理

测试环境:

windows8

MySQL5.6

Hibernate3

Hibernate批量插入

使用 Hibernate 将 一百万条记录插入到数据库的一个很天真的,错误的做法可能是这样的:

错误代码

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

for ( int i=0; i<1000000; i++ ) {
    MotherCat m = new MotherCat("明子","黑色");
    session.save(m);
}

tx.commit();
session.close();

这段程序要么运行一段时间会失败并抛出内存溢出异常(OutOfMemoryException) ,要么执行时间太长,导致效率低下。

这是因为 Hibernate 把所有新插入的MotherCat实例在 session 级别的缓存区进行了缓存的缘故。

解决:

首先,如果你要执行批量处理并且想要达到一个理想的性能,那么使用 JDBC 的批量处理功能是至关重要。JDBC 的批量抓取数量(batch size)参数设置到一个合适值:

<property name="hibernate.jdbc.batch_size">50</property>

注意,假若你使用了 identiy 标识符生成器,Hibernate会在 JDBC 级别透明的关闭插入语句的批量执行。

也可以在执行批量处理时完全关闭二级缓存

 <property name="hibernate.cache.use_second_level_cache">false</property>

但是,这不是绝对和必须的,因为我们可以显式设置 CacheMode 来关闭与二级缓存的交互。

正确代码:

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();       
for ( int i=0; i<1000000; i++ ) {
    MotherCat m = new MotherCat("明子","黑色");
    session.save(m);
    if ( i % 50 == 0 ) { //50, 和配置的JDBC batch size一样
        //刷出并同步到底层持久化, 批量的插入并且释放内存:
        session.flush();
        //完全清除session
        session.clear();
    }
}

tx.commit();
session.close();

以上代码虽然不会出现内存溢出,但效率不怎么好

优化代码

使用StatelessSession(无状态 session)接口

接口功能:

  1. 用托管对象的形式把数据以流的方法加入到数据库,或从数据库输出。
  2. 没有持久化上下文,也不提供多少高层的生命周期语义。
  3. 不实现和第一级cache(缓存),也不和第二级缓存,或者查询缓存交互。
  4. 不实现事务化写,也不实现脏数据检查。
  5. 不级联到关联实例。
  6. 忽略集合类(Collections)。
  7. 不触发 Hibernate 的事件模型和拦截器。
  8. 对数据的混淆现象免疫,因为它没有第一级缓存。
  9. 是低层的抽象,和低层 JDBC 相当接近。

以下给出优化代码

StatelessSession session = HibernateUtil.getSessionFactory().openStatelessSession();    //打开无状态的session
Transaction tx = session.beginTransaction();

for ( int i=0; i<1000000; i++ ) {
    MotherCat m = new MotherCat();
    m.setMname("大米");
    m.setColor("黑色");

    session.insert(m);
}

    tx.commit();
    session.close();

StatelessSession 接口定义的 insert(), update() 和 delete() 操作是直接的数据库行级别操作,其结果是立刻执行一条 INSERT, UPDATE 或 DELETE 语句。

因此,它们的语义和 Session 接口定义的 save(), saveOrUpdate() 和delete() 操作有很大的不同。

PS:更进一步的优化是使用原生SQL语句和StatelessSession接口结合的方式。可能还有其他优化方式,欢迎大家指教。

以上。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值