从业务逻辑隐藏Hibernate会话处理

时间:2014-07-21 17:44:06

标签: java hibernate

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

在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会话。

2 个答案:

答案 0 :(得分:0)

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

但是,如果记录的数量达到数百万,那么你很可能会遇到内存问题,那么你应该考虑共享缓存,逐页检索数据只需搜索n + 1和hibernate,你会发现关于这个主题的大量讨论。

我能想到的最简单的 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;
}

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

答案 1 :(得分:0)

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