浅谈Hibernate批量操作

在正式地介绍hibernate批量操作之前,先给大家普及一个hibernate重要的成员,即hibernate一级缓存,这个一级缓存不像二级缓存那样可插拔似的,是无条件使用的,这个缓存最大的一个作用就是在一个事务中,如果进行了n次对象保存的操作,都会缓存到hibernate的一级缓存区中,直至刷新缓存或提交事务,否则这些对象会一直存在于缓存中,好了,看下面这个例子:

EntityManager entityManager = null;
EntityTransaction txn = null;
try {
entityManager = entityManagerFactory().createEntityManager();

txn = entityManager.getTransaction();
txn.begin();

for ( int i = 0; i < 100000
; i++ ) {
Person Person = new Person( String.format( "Person %d", i ) );
entityManager.persist( Person );
}
txn.commit();
} catch (RuntimeException e) {
if ( txn != null && txn.isActive()) txn.rollback();
throw e;
} finally {
if (entityManager != null) {
entityManager.close();
}
}

上述操作例子会导致如下几个问题:

1、由于hibernate的一级session缓存会缓存所有新插入的用户实例,所以等到整个事务结束,持久化容器需要同时管理100000个对象,此时虚拟机分配的最大缓存相当小,那么这个操作例子将会引发OutOfMemoryException,而失败,虽然Java8允许分配更大的内存给缓存用;

2、长时间的事务运行会耗损连接池的性能,以至于其它的事务可能会得不到执行;

针对上述问题,我们可以周期性地调用Session的成员方法flush()和clear()方法,来灵活的控制一级缓存的大小,比如每当缓存25个对象调用一次,在提交刷新缓存对象记录的同时,清空缓存,看下面这个例子:

EntityManager entityManager = null;
EntityTransaction txn = null;
try {
entityManager = entityManagerFactory().createEntityManager();
txn = entityManager.getTransaction();
txn.begin();
int batchSize = 25;
for ( int i = 0; i < entityCount; ++i ) {
Person Person = new Person( String.format( "Person %d", i ) );
entityManager.persist( Person );
if ( i % batchSize == 0 ) {
//flush a batch of inserts and release memory
entityManager.flush();
entityManager.clear();
}
}
txn.commit();
} catch (RuntimeException e) {
if ( txn != null && txn.isActive()) 

txn.rollback();
throw e;
} finally {
if (entityManager != null) {
entityManager.close();
}
}

上述方法是很常见的一个解决一级缓存过大的方法,下面在让我们换个思路使用Hibernate的StatelessSession类来解决这个问题:StatelessSession是一个由Hibernate提供的,面向命令的API,使用它可以以游离对象的方式读取或存入数据,需要注意的是它不提供一级缓存,不与任意二级缓存或查询缓存交互,不提供自动的脏数据检查等,但是需要注意的是在某些情况或事务下,这个无状态的Session要比有状态的Session要快很多,其余限制请查阅相关文档,在此不多做叙述,看例子:

StatelessSession statelessSession = null;
Transaction txn = null;
ScrollableResults scrollableResults = null;
try {
SessionFactory sessionFactory = entityManagerFactory().unwrap( SessionFactory.class );
statelessSession = sessionFactory.openStatelessSession();

txn = statelessSession.getTransaction();
txn.begin();

scrollableResults = statelessSession.createQuery( "select p from Person p" )
.scroll(ScrollMode.FORWARD_ONLY);

while ( scrollableResults.next() ) {
Person Person = (Person) scrollableResults.get( 0 );
// 对Person对象的操作

XXX
statelessSession.update( Person );
}

txn.commit();
} catch (RuntimeException e) {
if ( txn != null && txn.getStatus() == TransactionStatus.ACTIVE) 

txn.rollback();
throw e;
} finally {
if (scrollableResults != null) {
scrollableResults.close();
}
if (statelessSession != null) {
statelessSession.close();
}
}

上述例子,正式利用的StatelessSession的特性,提出了一种新的解决缓存过大的思路,查询返回的客户实例会立即变为游离状态,他们不会与任何持久化容器关联,StatelessSession接口里面定义的insert、update、delete操作都是直接作用于数据库行,它们所出发的SQL操作会被立即执行,这一点与Session有着本质区别;

好了,先到这里吧!





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值