服务层实现中的Hibernate Evict

时间:2016-03-16 11:28:22

标签: hibernate

我有一个服务类

@Service
public class EmployeeServiceImplimplements EmployeeService {
....
....

通过员工Dao检索了大量员工记录,代码逐个迭代员工对象并进行各种操作。

Atlast我想要驱逐员工对象,因为它是一个昂贵的对象,内存正在增加。 }

请问如何调用逐出或正确的方法从内存中删除对象?

通常当hibernate会话可用时,我将调用hibernate.evict(emp);

提前致谢。

2 个答案:

答案 0 :(得分:0)

在这种情况下,您有一个EmployeeServiceImpl类与EmployeeDao进行交互以获取List<Employee>对象。随后,您遍历此列表并执行各种操作。问题是,这是一个非常庞大的列表,我们担心这个函数的内存利用率。

有了这个,假设您没有在列表中对这些员工实体进行制作,下面是我的观点。

  

Atlast我想要驱逐员工对象,因为它很贵   物体和记忆力正在增加。 }

如果List真的很大,你会看到Hibernate Session消耗的内存多于保存List<Employee>个对象所需的内存。主要原因是,Session必须以EntityEntry对象的形式维护每个Employee对象的状态,即每个Employee对象的一个​​额外对象EntityEntry。这是hibernate自动脏检查机制在刷新阶段工作以将实体的当前状态与其原始状态(存储在EntityEntry中)进行比较所必需的。

引用上述链接:

  

我们需要一个条目来告诉我们关于对象当前状态的所有信息   关于其持久状态实现警告:Hibernate   需要实例化此类的大量实例,   因此,我们需要注意它对内存消耗的影响。

但如果目的只是阅读并遍历员工列表而不执行和更改这些员工实体,我们可以使用StatelessSession代替Session

优点如上所述:

  

无状态会话也不实现第一级缓存   与任何二级缓存交互,也不实现   事务性后写或自动脏检查

没有自动脏检查,Hibernate不需要为EntityEntry的每个实体创建Employee,就像之前使用Session的情况一样。

说,它确实有自己的一组限制,如StatelessSession文档中所述。

但是,到目前为止,根据我对问题和假设的理解,我没有看到这些限制会造成任何问题或阻止使用StatelessSession instead of会话。

你提出的另一个选择:

  

我们可以在DaoImpl中编写一个方法来驱逐其中的对象   服务层?例如empDao.evict(emp);

当我们在empDao.evict(emp)上完成预定义的迭代次数时,我们可以定期从我们的empDao.evict(subListEmp)类调用EmployeeServiceImplList<Employee>这样的方法。在每20/50名员工左右迭代后。

如果你问我我的偏好,我宁愿采用StatelessSession方法,除非它的限制不允许我继续。如果StatelessSession对于当前问题不可行,由于其固有的局限性,我只会考虑在dao中暴露一些evict(..)并定期调用它。

答案 1 :(得分:0)

如果有理由继续使用有状态的StatelessSession,您还可以考虑使用其他一些替代方案,而无需费心Session

回调界面

在您的DAO类上公开一个方法,允许您提供一个回调接口的实现,该接口旨在逐个接受列表中的每个实体。

public interface EntityCallback<T> {
  boolean doWithEntity(T entity);
}

这里的想法是您的服务层可以使用上面的接口实现调用DAO方法,如下所示:

public <T> void findAll(EntityCallback<T> callback) {
  ScrollableResults<T> results = /* get result set*/

  int iterations = 0;
  while(results.hasNext()) {
    iterations++;
    T entity = results.next();
    if(!callback.doWithEntity(entity)) {
      break;
    }
    if(iterations % 100 == 0) {
      session.clear();
      iterations = 0;
    }        
  }
  results.close();
}

上述方法的优点在于它可以防止任何特定于hibernate的持久性构造泄露到服务层,而不会将业务逻辑推入数据访问层。

Wrap ScrollableResults Autoclosable Resources

有时,在事务内的服务层中迭代结果可能同样简单。通过在 ScrollableResults 类周围创建一个包装器,您可以使用try-with-resources。

public class QueryResult<T> implements Iterator<T>, AutoCloseable {
  /* add implementation stuffs */
}

然后在服务层内,您可以按如下方式使用它:

try( Iterator<Entity> it = dao.iterator(...) ) { 
  while( it.hasNext() ) {
    Entity entity = it.next();
  }
}

就像findAll(EntityCallback<T>)方法如何跟踪迭代次数一样,QueryResult类可以根据对next()的每次调用执行相同操作,因此可以自动清除会话具体间隔。

try-with-resources方法的好处是,因为它使用JDK7的AutoCloseable接口,所以服务层可以简单地将它用作迭代器,而不必关心底层结果集关闭它。