我有一个服务类
@Service
public class EmployeeServiceImplimplements EmployeeService {
....
....
通过员工Dao检索了大量员工记录,代码逐个迭代员工对象并进行各种操作。
Atlast我想要驱逐员工对象,因为它是一个昂贵的对象,内存正在增加。 }
请问如何调用逐出或正确的方法从内存中删除对象?
通常当hibernate会话可用时,我将调用hibernate.evict(emp);
提前致谢。
答案 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)
类调用EmployeeServiceImpl
或List<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
接口,所以服务层可以简单地将它用作迭代器,而不必关心底层结果集关闭它。