使用Hibernate回调的优点?

时间:2012-01-23 19:02:33

标签: java database hibernate spring

我无法理解使用Hibernate Callback方法的优点,是否有任何优势或特定用例我们应该去实现它。

public List findRecentRequests(final int offset, final int length)
{
    List list = getHibernateTemplate().executeFind(new HibernateCallback()
    {
        public Object doInHibernate(Session session) throws HibernateException
        {
            Query q = session.createQuery(FIND_RECENT_REQUESTS);
            q.setFirstResult(offset);
            q.setMaxResults(length);
            return q.list();
        }
    });
    return list;
}

另外一个更重要的问题是HibernateCallback方法在查询返回值后每次关闭会话吗?我有一个用例,每次刷新状态页面都会多次调用这个函数,所以每次打开会话和查询数据库都会这样,或者它会将查询结果存储在内存中,然后每当我调用这个函数时,都会弹出结果从记忆里。

我已阅读(Reference):

默认情况下,Spring HibernateTemplate.execute()会在完成时关闭所有打开的会话。与惰性初始化一起使用时,您可能会收到类似以下

的LazyInitializationException
  

org.hibernate.LazyInitializationException:无法初始化代理 - 没有会话

任何对相关文档部分的引用都将受到高度赞赏。

更新

在我的情况下,我使用ejb事务并将其设置为“支持”,我相信在这种情况下,事务被设置为支持,它是可选的,因此每次创建新会话时,hibernate将查询数据库以获得结果等等那是我的瓶颈,这是一个正确的假设吗?

3 个答案:

答案 0 :(得分:22)

关于使用HibernateCallback的原因。简短回答 - 它允许您访问当前事务绑定会话,以执行更复杂的休眠功能。大多数情况下HibernateTemplate上的简单方法就足够了,但有时您需要转到Session

这个难题有两个部分。

第一个是使用PlatformTransactionManager / TransactionTemplate OR @Transactional注释定义的事务范围。有关详细信息,请参阅spring docs / google。

第二个是,当你在一个交易中HibernateTemplate将使用一点魔法与当前交易进行交互。

因此像hibernateTemplate.save()这样的简单操作将参与交易。像您的示例更复杂也将参与交易。实际上,hTemplate上的任何方法都会参与其中。

了解会话何时关闭的问题

  • 如果您明确使用交易,请参阅上面的第一点,然后当交易范围关闭时,交易将被提交,会话将被关闭。
  • 如果没有事务,spring会在每次调用HibernateTemplate方法时为您创建一个会话,并在之后立即关闭它。这不是首选的方法,因为除非你做一些非常简单的事情,结果将从会话中分离出来,你将获得LazyInit异常。

在上面的第二个案例中需要注意的重点是没有明确的交易。您受连接的自动提交模式的支配,因此您可以在回调中执行保存,保存,抛出异常。第一次保存可能已经提交,没有交易就没有保证。

我的建议是,在进行任何更新时,请使用交易。

如果所有交易内容都是新手,请查看交易章节的春季文档。

答案 1 :(得分:6)

如果你还在使用Spring,你应该只在你的Repository或Service层周围使用declarative transaction management来透明地处理它。 PlatformTransactionManager实现将执行适合给定持久性提供程序的操作。

在您没有数据访问代码之后,依赖延迟集合进行初始化被认为是不好的做法 - 这通常意味着您在应用程序的控制器/视图层中有一些应该移入服务的业务逻辑层

答案 2 :(得分:0)

使用HibernateCallback并没有获得当前会话的真正优势,因为execute(...)要做的第一件事是:

...
session = obtainSessionFactory().getCurrentSession();
...

所以选择之间是一个品味问题

hibernateTemplate.execute(session -> session.createQuery(...));

hibernateTemplate.getSessionFactory().getCurrentSession().createQuery(...));

或使用辅助方法getSession()

getSession().createQuery(...));

您的代码也可能看起来像

@Transactional(readOnly = true)
public List findRecentRequests(final int offset, final int length) {
    Query q = getSession().createQuery(FIND_RECENT_REQUESTS);
    q.setFirstResult(offset);
    q.setMaxResults(length);
    return q.list();
}