2016-03-16 49 views
0

我有一个服务类休眠逐出在服务层实现

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

庞大的员工记录已通过员工道被检索和代码遍历一个接一个员工对象,做各种操作..

Atlast我想驱逐员工对象,因为它是一个昂贵的对象,内存越来越大。 }

请问如何调用evict或正确的方法从内存中删除对象,请帮助我吗?

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

在此先感谢。

+0

看起来你可以尝试[StatelessSession](https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/StatelessSession.html)作为无状态会话不实现第一级缓存和与“会话”相比,重量轻。虽然它有一些限制,如链接中指定的 –

+0

您可以粘贴一段代码片段或示例或链接以供参考吗? – Kathiresa

+0

请参阅** [无状态会话]的第13.3节**(https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html) –

回答

0

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

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

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

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

报价表上面的链接:

我们需要一个条目来给我们讲讲对象 的当前状态,相对于它的持久状态实施警告:休眠 需要实例高量这个类的实例, 因此我们需要考虑它对内存消耗的影响。

但如果目的是为只读,并通过员工的列表迭代和不执行和修改这些员工的实体,我们可以用StatelessSession而不是Session

的优点是从上面的链接引用:

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

由于没有自动脏检查没有必要让Hibernate创建EntityEntry被保持的Employee每个实体,因为它在前面的情况下做了与Session

表示它具有自己的一套限制,如StatelessSession文档中所述。

但是,到目前为止,根据我对问题和假设的理解,我没有看到这些限制会带来任何问题或妨碍使用StatelessSession instead of Session`。

另一种选择,你长大:

我们可以写在DaoImpl的方法驱逐这是 服务层的对象?示例empDao.evict(emp);

肯定我们能有像empDao.evict(emp)empDao.evict(subListEmp)的方法,我们可以从我们的EmployeeServiceImpl类定期调用,因为我们在List<Employee>完成迭代的预定数量,每个员工20/50左右迭代后说。

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

+0

org.springframework.transaction.CannotCreateTransactionException:无法打开Hibernate Session进行事务处理;嵌套的例外是org.hibernate.exception.JDBCConnectionException:无法打开连接 \t在org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:515) \t在org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction (AbstractPlatformTransactionManager.java:373) \t at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:420) – Kathiresa

+0

@Kathiresa您可以将完整的堆栈跟踪添加到您的问题吗?这将有所帮助。另一方面,你可能想考虑把整个stacktrace和你的hibernate配置文件/类作为一个新问题来发布,而不是使用这个。对我来说,它看起来像一些配置/设置问题,可能不直接涉及我们在这个问题上有关'evict'的相关讨论。 –

+0

我们可以在@service类中添加entitymanager并调用evict吗?因为我不认为我们可以使用无状态会话,因为会话也会更新 – Kathiresa

0

如果您有理由继续使用有状态的Session,您可以考虑使用StatelessSession

回调接口

你的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(); 
} 

上述方法的好处是,它可以防止泄露任何休眠专用持久性构造到服务层,而不实际将业务逻辑推入数据访问层。

裹的ScrollableResults Autoclosable资源

可能有次它可能只是简单迭代在事务内的服务层的结果。通过在类的周围创建一个包装,你可以利用试用资源。

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(),因此可以按特定间隔自动清除会话。

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