使用StatelessSession进行批处理

17

来自文档

如果我们需要插入100万行/对象的情况:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();
为什么我们应该使用这种方法?与StatelessSession相比,它带来了哪些好处?
为什么要用这种方法?与StatelessSession相比,它有何好处?
    StatelessSession session = sessionFactory.openStatelessSession();
    Transaction tx = session.beginTransaction();

    for ( int i=0; i<100000; i++ ) {
      Customer customer = new Customer(.....);
      session.insert(customer);
    }    

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

我的意思是,这个("替代方案")示例并不使用内存,也不需要同步,清除缓存,那么这难道不应该是这种情况下的最佳实践吗?为什么要使用前面的那个呢?


1
你的这两个例子做的完全不同 - 第一个插入了一堆新对象,第二个查询了一些现有的对象并更新了它们。如果它们做相同的事情,会更清楚地说明你的问题。 - Tom Anderson
嗨,@ses!我有一个类似的问题。无意中发现了你的帖子 :) - pubsy
3个回答

12

根据您提供的文档:

 

特别是,无状态会话不实现一级缓存,也不与任何二级或查询缓存交互。它不实现事务写后或自动脏检查。使用无状态会话执行的操作永远不会级联到相关实例。无状态会话忽略集合。通过无状态会话执行的操作绕过了Hibernate的事件模型和拦截器。由于缺乏一级缓存,无状态会话容易受到数据别名效应的影响。

这些都是一些重要的限制!

如果您要创建的对象或所做的修改仅是单个对象的标量字段的简单更改,则我认为与批量常规会话相比,无状态会话没有任何缺点。但是,一旦您想要执行一些更复杂的操作-如操纵对象的集合值属性或从第一个级联的另一个对象等-那么无状态会话对您而言可能更加阻碍而不是帮助。

更一般地说,如果批量普通会话提供的性能足够好,则无状态会话只是不必要的复杂性。它看起来有点像普通会话,但具有不同的API和语义,这种情况往往会引发错误。

当然,可能存在适用它的情况,但我认为这些情况是例外而不是规则。


5
如果我在一秒钟内插入了10000条记录,然后立即清除该缓存,那么为什么我需要一级缓存呢?我猜,在那么短的时间内,没有人有机会使用它。我认为,需要一些好的例子来理解它……简而言之,我认为:无状态会话适用于最简单的情况,适用于不需要保存复杂对象的情况。 - ses
2
另外,我找到了一些解释证明了你的观点:http://javainnovations.blogspot.ca/2008/07/batch-insertion-in-hibernate.html - ses

1
无状态会话在性能方面比会话具有优势,因为无状态会话将跳过用于Session对象的事务提交或会话刷新方法。但是,重要的是要注意服务/DAO不应尝试对父对象或任何子对象执行会话内数据操作。这将引发异常。此外,请确保显式关闭会话,否则将导致泄漏的连接。
为了获得更好的无状态会话性能,如果使用Spring驱动的事务,则将Spring事务标记为只读,并将传播设置为NEVER。
但是,再次强调,在必须操作对象模型的情况下,请勿尝试此操作。
@Transactional(value="someTxnManager", readOnly=true, propagation=Propagation.NEVER)
    public List<T> get(...) {

        return daoSupport.get(...);
    }

在daoSupport中。
StatelessSession session = sessionFactory.openStatelessSession();
try{
// do all operations here
}
...
...
finally{
            session.close();
}

它跳过了提交和刷新?你确定吗? - Jess
在Spring中,基于AOP的@Transactional机制中,如果在事务提交之前调用了session.close(),这将导致异常。 - borino

-10

StatelessSession 不支持批处理。
如果我没看错的话,我在文档中看过这个内容。
StatelessSession 不提供以下功能和行为
• 第一级缓存
• 与任何第二级缓存或查询缓存的交互
• 事务性写入后处理或自动脏数据检查

批处理是通过缓存进行的。
如果我说错了,请原谅我。


4
您的答案是不正确的- StatelessSessions 是使用 NHibernate 进行批处理的首选选择。请查看http://ayende.com/blog/4137/nhibernate-perf-tricks以获取更多信息。 - Rich O'Kelly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接