在多线程环境中与Hibernate会话进行交互的合适方式

时间:2018-05-31 18:39:56

标签: hibernate hibernate-5.x

Web应用程序等多线程环境的上下文,每当需要使用Hibernate使用会话时,获取会话的最佳方式是getcurrentsession()还是opensession()?

就像在这里opensession vs getcurrentsession一样,它已经提到过getcurrentsession不能在Web应用程序中使用。

虽然会话不是安全的,但由于这个原因它不适合使用getcurrentsession吗?是否需要使用opensesion并提交&手动关闭冲洗?

我需要明确澄清。谢谢大家。

PS:我使用了Spring Boot App的hibernate进行测试。

1 个答案:

答案 0 :(得分:2)

如果您的类路径中有spring-boot-autocofigure,则可能已为您配置EntityManagerFactory。如果您的类路径上没有这个,那么将SessionFactory的bean配置转换为EntityManagerFactory非常容易。完成之后,只需在spring bean中执行以下操作即可获得超级实例

@Service
public class MyBookServiceImpl implements BookService {
  @PersistenceContext
  private EntityManager entityManager;

  @Transactional
  public void doSomeFancyHibernateThing() {
    List<Book> allBooks = entityManager.createQuery( "FROM Book", Book.class )
       .getResultList();
  }
}

此时,您可以向服务类添加任何方法,以便执行该bean实现和使用EntityManager实例所需的任何任务。您不需要关心多个线程等,因为spring会自动为您提供EntityManager的实例,该实例可以安全地在该线程中使用而无需考虑其他线程。

注意我在这里说那个帖子是安全的。不要试图在另一个线程中使用该实例,并期望不存在复杂性或问题

如果您认为必须使用SessionFactory,无论出于何种原因,您都可以使用这两种方法中的任何一种,具体取决于您 希望管理会话生命周期的程度。

如果你想使用#getCurrentSession(),重要的是你还提供以下配置休眠,以便它将当前会话查找与线程局部变量绑定,确保每个线程都给出自己的会话对象: / p>

  

的hibernate.current_session_context_class =螺纹

使用上述内容的好处是您无需担心Session的生命周期管理,它将自动关闭&amp;在您的交易结束时发布。

例如:

@Transactional
public void doSomeFancyHibernateThing() {
  Session session = sessionFactory.getCurrentSession();
  // do something here, when the method exits, the session is closed & destroyed.
}

如果要使用#openSession(),则返回的Session对象的生命周期和生命周期将在您身上,以保证您处理正确关闭其资源的问题。换句话说,上面这个简单的方法就变成了这个:

public void doSomeFancyHibernateThing() {
  Session session = sessionFactory.openSession();
  try {
     // do something here
  }
  catch ( Exception e ) {
     // do whatever
  }
  finally {
    if ( session != null && session.isOpen() ) {
      session.close();
    }
  }
}

正如您所看到的,答案顶部的JPA等价物与getCurrentSession()与一个hibernate配置配对时的使用非常相似。

这里的强大好处是使用JPA(顶部的示例)直接删除Hibernate上的所有依赖项。如果您发现您遇到需要JPA未公开的特定于Hibernate的特性的用例,您仍然可以通过如下解开EntityManager来轻松获取会话:

Session session = entityManager.unwrap( Session.class );
// do whatever you need with a session easily.