【问题标题】:Manage Hibernate Sessions With Spring使用 Spring 管理 Hibernate 会话
【发布时间】:2012-09-24 12:16:33
【问题描述】:

我有很多关于休眠会话的问题要问,因为我一直遇到问题。

我正在使用 Spring 3.1.1 和 Hibernate 4.1.3。

首先是我正在处理的类图。

代码类:

public class Equipement {

  @ManyToOne(fetch = FetchType.LAZY)
  @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
  public getOffice(){
    return office ;
  }

public class Office {    
  @ManyToOne(fetch = FetchType.LAZY)
  @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
  public getService(){
    return service ;
  }

public class Service {
  @ManyToOne(fetch = FetchType.LAZY)
  @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
  public getDepartement(){
    return departement ;
  }

这是我加载所有设备的方式。

public class HibernateEquipementDao{

  @SuppressWarnings("unchecked")
  public List<Equipement> getAll() {
      return sessionFactory.getCurrentSession().createQuery("from Equipement").list() ;
  }
}

假设我将所有设备加载到 List&lt;Equipement&gt; allEquipements 中,并希望仅使用某些服务或某些部门的设备填充我的视图。

 List<Equipement> aListOfEquipements = new ArrayList<Equipement>() ;
 for(Equipement equipement : allEquipements)
   if(equipement.getOffice().getService().getName().equals("name"))
     aListOfEquipements.add(equipement) ;

我真的可以随时这样做吗?名为 Current 的会话始终处于活动状态? 有时我会得到那个例外。 org.hibernate.LazyInitializationException: 无法初始化代理 - 没有会话

这让我问我的 EquipementDao 使用的当前会话在哪里?

当我想获得设备部门时,有没有办法打开会话?

或者还有其他方法可以继续吗?如何管理会话以及如何加载我的所有设备并毫无问题地访问其他实体?

【问题讨论】:

    标签: spring hibernate session spring-mvc


    【解决方案1】:

    为服务添加层,我知道这个名字在你的情况下不是那么幸运,但是在这个层中你将有负责你的逻辑的类。

    一些原型:

    public class EquipmentService {
    
       @Inject
       private HibernateEquipementDao dao;
    
       @Transactional
       public List<Equipement> doSomethingWithEquipmentWithoutLazyException(Equipment equipment){
          List<Equipement> allEquipments = dao.getAll();
    
          List<Equipement> aListOfEquipements = new ArrayList<Equipement>() ;
          for(Equipement equipement : allEquipements) {
             if(equipement.getOffice().getService().getName().equals("name")) {
                 aListOfEquipements.add(equipement) ;
             }
          }
          return aListOfEquipments;
       }
    
    }
    

    非常重要的是注解:@Transactional 表示会话将在方法开始时打开并在方法结束时关闭,因此无法抛出 LazyLoadingException。

    一些关于 Transactonal 的有趣线程:Where does the @Transactional annotation belong?

    【讨论】:

    • 那个注解简直太神奇了,太棒了,所以每当我有一个方法在我的服务层中执行一些事务操作时,我最好把那个注解放在第一位。
    • LazyLoadingException 又回来了,现在是因为我的jsp中的SpEL表达式${equipement.office.name}...
    • 使用 @Transactional 注释完成方法后,会话关闭。因此,如果您没有初始化“office”,那么您将得到 LazyLoadingException。在调试中运行你的应用程序,你会看到。
    【解决方案2】:

    我已经看到了解决这个问题的两种方法。

    1.在视图中打开会话

    您可以在视图中配置您的休眠设置打开会话。 如果你以编程方式配置你的休眠,你可以使用这一行:

    jpaProperties.put(org.hibernate.cfg.Environment.ENABLE_LAZY_LOAD_NO_TRANS, true)
    

    另一种方法是在 web.xml 中声明一个过滤器,如下所示:

        <filter>
            <filter-name>OpenEntityManagerInViewFilter</filter-name>
            <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>OpenEntityManagerInViewFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    

    这种方法会影响您的所有系统,并可能影响您的性能。

    2。获取加入:

    您可以在查询中使用 FETCH JOIN 来强制休眠加载数据,例如:

    from Equipement e FETCH JOIN e.office
    

    这种方法会更难做(您的系统中的许多点都会受到影响)并且要小心。

    3.查询返回后调用get方法:

    在您的 DAO 中,您可以在查询返回后调用 get 方法。我不喜欢这种方式,但正常工作。

    好吧,我希望我能帮助你。

    【讨论】:

    【解决方案3】:

    对于大多数 Web 应用程序来说,让当前事务跨越整个请求是最简单且绝对合适的。最简单的方法是有一个过滤器来启动事务并在请求结束时提交/回滚。在 Spring/Hibernate 中,这称为 Open Entity in View 模式。 Spring 通过 org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter 提供了一个过滤器实现。

    当使用这种方法时,视图(即您的 JSP)参与相同的事务并且不需要重新加载并且在 fetchtype LAZY 关系的情况下也可以导航实体。

    【讨论】:

    • 我已经用另一种方法解决了这个问题,我发现我也可以使用 Interceptor 所以我使用了这个:&lt;bean class="org.springframework.orm.hibernate4.support.OpenSessionInViewInterceptor"&gt;
    • 太棒了。对不起,我不是很精确。如果您不受 JPA 约束,您可能正在使用 Hibernate 特定版本,即基于 Hibernate 会话而不是实体管理器。该拦截器 AFAICT 确保事务从请求开始到结束,与(标记为)答案中的方法实现的仅控制器(与视图)操作形成对比。
    猜你喜欢
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    • 1970-01-01
    • 2013-03-14
    • 2016-10-26
    • 2020-12-16
    • 2012-04-30
    相关资源
    最近更新 更多