2016-03-16 50 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接口,服務層可以簡單地將它用作迭代器,而不必關心底層結果集並關閉它。