微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Hibernate Search:在没有数据库事务的情况下执行搜索查询

如何解决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 举报,一经查实,本站将立刻删除。