我无法理解使用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()会在完成时关闭所有打开的会话。与惰性初始化一起使用时,您可能会收到类似以下
的LazyInitializationExceptionorg.hibernate.LazyInitializationException:无法初始化代理 - 没有会话
任何对相关文档部分的引用都将受到高度赞赏。
更新
在我的情况下,我使用ejb事务并将其设置为“支持”,我相信在这种情况下,事务被设置为支持,它是可选的,因此每次创建新会话时,hibernate将查询数据库以获得结果等等那是我的瓶颈,这是一个正确的假设吗?
答案 0 :(得分:22)
关于使用HibernateCallback
的原因。简短回答 - 它允许您访问当前事务绑定会话,以执行更复杂的休眠功能。大多数情况下HibernateTemplate
上的简单方法就足够了,但有时您需要转到Session
。
这个难题有两个部分。
第一个是使用PlatformTransactionManager
/ TransactionTemplate
OR @Transactional
注释定义的事务范围。有关详细信息,请参阅spring docs / google。
第二个是,当你在一个交易中HibernateTemplate
将使用一点魔法与当前交易进行交互。
因此像hibernateTemplate.save()
这样的简单操作将参与交易。像您的示例更复杂也将参与交易。实际上,hTemplate上的任何方法都会参与其中。
了解会话何时关闭的问题
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();
}