1

我一直在我的 Spring/Hibernate 应用程序中使用会话工厂(注入 DAO 对象的单例 Bean),我正在使用服务层架构,并且遇到以下问题:

每当我从数据库中获取域对象时,它都会使用休眠会话工厂提供的新会话。在多次请求同一行的情况下,这会导致具有同一域对象的多个实例。(如果使用单个会话,它将返回指向同一引用的多个对象)因此,对这些域对象之一所做的任何更改都不会被表示同一行的其他域对象考虑在内。

我正在开发一个具有多个视图的 SWING 应用程序,并且我从不同的位置(和查询)获得相同的数据库行,因此我需要获取指向同一实例的域对象。

那么我的问题是,这是使用 SessionFactory 实现这一点的一种方法吗?如果没有,对我的整个应用程序使用单个会话是否是一种好习惯?在这种情况下,我应该如何以及在哪里声明这个会话?(应该是像 sessionFactory 一样注入到 DAO 对象中的 bean 吗?)

预先感谢您的帮助

4

2 回答 2

0

您正在View Pattern 中寻找Open Session 。本质上,您希望在应用程序启动时将 Session 绑定到您的线程,并在应用程序的整个生命周期中使用相同的 Session。您可以通过创建一个像这样保持会话的单例 util 类来做到这一点(请注意,我使用的示例使用 anEntityManager而不是 a Session,但您的代码将基本相同):

  private static EntityManager        entityManager;

  public static synchronized void setupEntityManager() {
    if (entityManager == null) { 
      entityManager = entityManagerFactory.createEntityManager();
    } 

    if (!TransactionSynchronizationManager.hasResource(entityManagerFactory)) {
      TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(entityManager));
    }
  }

  public static synchronized void tearDownEntityManager() {
    if (entityManager != null) { 
      if (entityManager.isOpen()) { 
        entityManager.close();
      } 

      if (TransactionSynchronizationManager.hasResource(entityManagerFactory)) { 
        TransactionSynchronizationManager.unbindResource(entityManagerFactory);
      } 

      if (entityManagerFactory.isOpen()) { 
        entityManagerFactory.close();
      } 
    } 
  }

请注意,与 Open Session in View 模式相关的固有风险。例如,我在评论中注意到您打算在应用程序中使用线程。会话不是线程安全的。因此,您必须确保您没有尝试以线程方式访问数据库。*

您还必须更加了解您的集合获取策略。通过打开会话和延迟加载,您总是有可能在数据库上施加过多的负载。

*我以前在 NetBeans 应用程序中使用过这种方法,我知道它使用线程处理某些任务。我们从来没有遇到过任何问题,但是您需要注意风险,其中有很多。

编辑

根据您的情况,也可以从 Session 中驱逐您的域对象并缓存分离的对象以供以后使用。这种策略要求您的域对象不要经常更新,否则您的应用程序将变得不必要地复杂。

于 2012-05-05T20:11:44.397 回答
0

Spring 中的 Hibernate 会话(我将其称为 h-session)通常绑定到线程(请参阅 JavaDoc for HibernateTransactionManager),因此每个线程获取一次 h-session。

如果您在一个 h-session 上多次调用“get”或“load”,则第一级缓存(h-session 缓存 - 始终打开)用于检索相同的对象。但是这个缓存不适用于查询。

此外,您不应该忘记与事务隔离相关的问题。在大多数应用程序中,使用“已提交读”隔离级别。而这种隔离级别受称为“不可重复读取”的现象影响。基本上,如果您多次查询该行,您可以在一个事务中收到同一行的多个版本(因为可以在另一个事务中的查询之间更新行)。

因此,您不应该在一个 h-session/transaction 中多次查询相同的数据。

于 2012-05-05T19:14:07.187 回答