如何解决Hibernate Search:在没有数据库事务的情况下执行搜索查询
我在 Spring Boot 项目中使用 Hibernate Search 5.11.5。对于搜索,我使用投影,所以理论上我不需要开放交易。但是如果我删除 @Transactional
注释并调用 Search.getFullTextEntityManager(em)
,我会得到异常
java.lang.IllegalStateException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:288)
at com.sun.proxy.$Proxy142.unwrap(UnkNown Source)
at org.hibernate.search.jpa.Search.getSession(Search.java:55)
at org.hibernate.search.jpa.Search.getFullTextEntityManager(Search.java:49)
因为我因此使用了投影 - 有没有办法防止这种强制使用交易?
解决方法
问题
有点复杂,但我会尽力解释...
是的,Hibernate Search 能够在没有事务的情况下运行搜索查询。即使您正在加载实体,但显然不推荐这样做。无论如何,如果您只是使用投影而不加载任何实体,那绝对是可能的。
然而,Hibernate Search 总是需要一个 Session,即使它没有加载任何实体。让我们称之为内部架构的限制。所以你不需要交易,但你需要一个会话。
现在,Spring 注入的实体管理器有点特殊,因为它们是代理。注入到您的 bean 中的 EntityManager
代理将自动创建一个真正的 EntityManager
并委托给它...但前提是您处于事务中。如果您不在交易中,则会收到您所看到的错误。
所以并不是 Hibernate Search 直接需要一个事务,而是它需要一个实际的 EntityManager
(不仅仅是一个代理),而且(至少在默认情况下)Spring 只会允许在交易中这样做。
解决方案...?
我建议您重新考虑并使用事务,除非您有非常具体的原因不想这样做,例如有限的数据库连接池。
否则...
可能在 Spring 内部构建了解决方案。 OpenEntityManagerInViewFilter
浮现在脑海中,尽管这是一个有争议的解决方案。也许还有其他人,但不幸的是,我对 Spring 有点生疏。
或者,您可以尝试自己打开 Session
。只要您不加载任何内容并且不打开事务,它的性能就应该相当便宜(特别是它不会获得数据库连接)。我想这就是你想要的吗?
它会是这样的:
@PersistenceUnit
EntityManagerFactory entityManagerFactory;
public List<MyProjection> search(...) {
try (Session session = entityManagerFactory.unwrap(SessionFactory.class)
.openSession()) {
// ... do your things ...
return hits;
}
}
最终,在未来的某个时候,将有一个专门的 API 用于无会话(因此无事务)搜索查询:https://hibernate.atlassian.net/browse/HSEARCH-3519 但是现在,上面的解决方案将不得不做。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。