当前位置: 首页 > 知识库问答 >
问题:

Spring和Hibernate SessionFactory的问题:域对象范围限制为会话

车思淼
2023-03-14

我在Spring/Hibernate应用程序中使用了会话工厂(注入DAO对象的单例Bean),我使用的是服务层架构,我有以下问题:

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

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

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

提前感谢您的帮助

共有2个答案

云炜
2023-03-14

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

  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();
      } 
    } 
  }

请注意,视图模式中的开放会话存在固有风险。例如,我在评论中注意到,您打算在应用程序中使用线程。会话不是线程安全的。因此,您必须确保没有试图以线程方式访问数据库*

您还必须更加了解集合的抓取策略。在开放会话和延迟加载的情况下,您总是有可能对数据库施加过多的负载。

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

编辑

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

汪飞捷
2023-03-14

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

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

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

因此,您不应该在一个h会话/事务中多次查询相同的数据。

 类似资料:
  • 我们知道Spring框架提供了单例、原型、请求、会话、全局会话bean范围。 我们还知道Spring Web流提供了flow Scope、viewScope、Request estScope、flash Scope、versationScope。 因此,如果我在spring MVC项目中提到一个组件,比如说Student,作为@Component@Scope=singleton。对于每个请求,它会

  • 问题内容: 上面的查询将返回前10个等级。 如何修改,或者是否存在另一种语法来查询第10位到第20位? 问题答案: 这真的是基本的东西。您应该使用: http://dev.mysql.com/doc/refman/5.5/en/select.html 两个参数10,10是(Offset,Limit),因此它将检索第11-20行。 9,11将需要获得第10-20名。

  • 我试图在会话范围内创建一个Spring bean: 当我尝试在servlet过滤器中从Application Context获取类时,如下所示: 我收到以下错误: 如果我将范围定义为< code>prototype,就不会有任何问题!如何从applicationContext中检索会话范围的spring bean?

  • 我有两个HTML中的下拉列表(简化)如下所示: 我想限制这些输入,以便当用户在第一个下拉列表中选择“三”时,值“一”和“二”在第二个下拉列表中被完全删除(或禁用),反之亦然:当用户在第二个下拉列表中选择“四”时,我想从第一个下拉列表中删除“五”。(有点像一个范围滑块) 我知道这应该可以通过一些jQuery代码,但谁能解释一下怎么做? 编辑: 添加了一些我曾经使用过的jQuery代码,我可以选择当前

  • 在我的应用程序中,我使用“Drive.file”作用域来访问用户的谷歌驱动器。我在google drive中共享了几个由我的应用程序创建的用户文件。现在,一旦与用户共享了一个文件,该用户就无法访问该文件,因为“Drive.file”作用域表示“404 file not Found”错误。但是当我用完全驱动器访问替换作用域时,文件是可访问的。那么,它们是我使用限制性范围以及检索/访问应用程序用户之间

  • NutIoc 实现了 Ioc2 接口,它继承自 Ioc 接口,并多出了两个方法。 一个允许你自行添加自定义的值类型,另一个是允许你在获取对象时,链入自己的上下文环境 请阅读 org.nutz.ioc.IocContext 的接口文档, 你可以根据需要实现这个上下文接口 这个设计有什么用? 比如,在一个 Web 应用中,你希望在会话中保存一个数据源,你不希望这个数据源保存在 Application