【问题标题】:Hide Hibernate session handling from business logic从业务逻辑中隐藏 Hibernate 会话处理
【发布时间】:2014-07-22 02:42:27
【问题描述】:

假设我有一个实体“父”,它包含一个“子”对象列表。

在 Java 中是这样的:

public class ParentEntity implements Parent {
   protected int id;
   @Override
   public int getId() { return id; }
   @Override
   public void setId(int id) { this.id = id; }

   protected List<Child> children;
   @Override
   public List<Child> getChildren() { return children; }
   @Override
   public void setChildren(List<Child> children) { this.children = children; }

   @Override
   public void save() {
      // Do some Hibernate "save" magic here...
   }

   public static Parent getById(int id) {
      Session session = HibernateUtil.getSessionFactory().openSession();
      Parent entity = (Parent) session.get(ParentEntity.class, id);
      session.close();
      return entity;
   }
}

我的业务逻辑类只能与接口类一起使用,如下所示:

public class BusinessLogic {
   public void doSomething() {
      Parent parent = ParentEntity.getById(1);
      for (Child c : parent.getChildren())
         System.out.println("I love my daddy.");
   }
}

不幸的是,这不起作用,因为父级的子级没有加载,并且循环因 NullPointerException 而崩溃。

1。方法“急切加载”

这种方法有两个问题。即使在 XML 中我写了“lazy='false'”,Hibernate 似乎也忽略了这一点。 其次,在我的情况下,急切加载是不可取的,因为我们可能有数百个孩子。

2。方法“在 'GET' 上加载/初始化”

@Override
public List<Child> getChildren()
{
   if (!Hibernate.isInitialized(children)) {
      Session session = HibernateUtil.getSessionFactory().openSession();
      Hibernate.initialize(children);
      session.close();
   }
   return children;
}

这也不起作用,因为我收到一个异常说该集合未链接到会话。之前用于加载父实体的会话已关闭。

您认为这里的“最佳实践”解决方案是什么?我真的不想在我的业务逻辑中弄乱 Hibernate 会话。

【问题讨论】:

  • 您能解释一下为什么不能选择急切加载吗?您甚至可以为您的具体用例使用自定义查询。

标签: java hibernate


【解决方案1】:

您可以使用查询对象或自定义查询,并在您真正需要它们的场景中获取所有子对象(搜索 left join fetch),这可能适用于几千个对象。

但是,如果记录的数量可能达到数百万,您很可能会遇到内存问题,那么您应该考虑共享缓存,逐页检索数据只需搜索 n+1 并休眠,您就会发现围绕这个话题进行了大量讨论。

我能想到的最简单的hack

public static Parent getParentWithChildrenById(int id) {
  Session session = HibernateUtil.getSessionFactory().openSession();
  Parent entity = (Parent) session.get(ParentEntity.class, id);
  Hibernate.initialize(entity.children);
  session.close();
  return entity;
}

旁注:在域层中拥有数据访问逻辑被认为是不好的做法。

【讨论】:

    【解决方案2】:

    我一直允许 Spring 和 JPA 管理我的 Hibernate 会话,因此大部分痛苦的样板代码在那时都消失了。但是您仍然必须在退出会话打开的数据层调用之前调用entity.getChildren().size()(或类似的东西),以强制 Hibernate 在仍有会话可用时进行检索。

    【讨论】:

      猜你喜欢
      • 2011-02-07
      • 2011-06-21
      • 2012-07-04
      • 2016-11-14
      • 1970-01-01
      • 1970-01-01
      • 2012-05-04
      • 2019-12-23
      • 1970-01-01
      相关资源
      最近更新 更多