首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >服务层实现中的Hibernate Evict

服务层实现中的Hibernate Evict
EN

Stack Overflow用户
提问于 2016-03-16 19:28:22
回答 2查看 353关注 0票数 0

我要上服务班

代码语言:javascript
复制
@Service
public class EmployeeServiceImplimplements EmployeeService {
....
....

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

最后,我想驱逐employee对象,因为它是一个开销很大的对象,而且内存也在不断增加。}

你能告诉我如何调用驱逐或从内存中移除对象的正确方法吗?

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

提前谢谢。

EN

回答 2

Stack Overflow用户

发布于 2016-03-16 22:43:45

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

这样,假设您没有对列表中的这些employee实体进行操作,下面是我的观点。

最后,我想驱逐employee对象,因为它是一个开销很大的对象,而且内存也在不断增加。}

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

以上链接引用:

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

但是,如果目的只是读取和迭代employee列表,而不是对这些employee实体执行和更改,那么我们可以使用StatelessSession而不是Session

优势是从上面的链接中引用的:

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

由于没有自动脏检查,Hibernate不需要为Employee的每个实体创建要维护的EntityEntry,就像之前使用Session时所做的那样。

也就是说,正如StatelessSession文档中提到的那样,它确实有自己的一组限制。

但是,到目前为止,根据我对这个问题的理解和我所做的假设,我认为这些限制不会带来任何问题,也不会阻止使用StatelessSessioninstead ofSession`。

您提出的另一个选项:

我们能用DaoImpl写一个方法来驱逐服务层中的对象吗?示例empDao.evict(emp);

当然,我们可以有一个像empDao.evict(emp)empDao.evict(subListEmp)这样的方法,当我们在List<Employee>上完成预定义的迭代次数时,比如每20/50名员工迭代一次,我们就可以从我们的EmployeeServiceImpl类中定期调用它们。

如果你问我的偏好,我更倾向于使用StatelessSession方法,除非它的局限性不允许我继续。如果由于其固有的局限性,StatelessSession对于当前的问题不可行,那么我才会考虑在dao中公开一些evict(..)并定期调用它。

票数 0
EN

Stack Overflow用户

发布于 2016-03-18 10:28:34

如果有理由继续使用有状态的StatelessSession,您也可以考虑一些替代方案,而不必费心使用Session

回调接口

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

代码语言:javascript
复制
public interface EntityCallback<T> {
  boolean doWithEntity(T entity);
}

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

代码语言:javascript
复制
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的持久性构造泄漏到服务层,而不会真正将业务逻辑推入数据访问层。

包裹ScrollableResults可自动关闭资源

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

代码语言:javascript
复制
public class QueryResult<T> implements Iterator<T>, AutoCloseable {
  /* add implementation stuffs */
}

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

代码语言:javascript
复制
try( Iterator<Entity> it = dao.iterator(...) ) { 
  while( it.hasNext() ) {
    Entity entity = it.next();
  }
}

findAll(EntityCallback<T>)方法跟踪迭代次数非常相似,您的QueryResult类可以根据对next()的每次调用执行相同的操作,因此可以在特定的时间间隔自动清除会话。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36034381

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档