簡體   English   中英

休眠批處理更新-實體未更新

[英]Hibernate Batch Update - Entities are not updated

我有一個批處理過程,它正在重新計算一組實體的數據。 實體列表是通過休眠從數據庫中獲取的:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void recalculateUserData(Long userId){
    List<Entity> data = repository.getAllPendingRecalculation(userId);

    List<Entity> recalculated = new LinkedList();

    for (Entity entity : data){
        recalculateEntity(entity, recalculated);
        recalculated.add(entity);
        flushIfNeeded(recalculated); //every 10 records
    }
}

private void recalculateEntity(Entity entity, List<Entity> recalculated){
    //do logic
}

private void flush(){
    getSession().flush();
    getSession().clear();
}

private void flushIfNeeded(List<Entity> data) {
    int flushSize = 10
    if (data.size() % flushSize == 0){
        flush();
    }
}

該過程運行時,看起來某些實體變得分離,從而導致兩個症狀:

  1. 嘗試獲取惰性數據時,出現異常: org.hibernate.LazyInitializationException - could not initialize proxy - no Session
  2. 當不需要惰性加載時-即使flushIfNeeded(...)工作正常,DB中僅更新前10條記錄。

在我的第一次嘗試中,我嘗試通過在recalculateEntity(...)內調用session#refresh(entity)來解決該問題-這解決了延遲初始化問題,但#2中的問題仍然發生:

private void recalculateEntity(Entity entity){
    getSession().refresh(entity);
    //do logic
}

既然這還沒有解決問題,我考慮過要使用attach(entity)而不是refresh(entity)

private void recalculateEntity(Entity entity){
    getSession().attach(entity);
    //do logic
}

這似乎可行,但是我的問題是: 為什么這些實體首先被分離?

(我正在使用Hibernate 3.6.10)


更新

正如@galovics解釋的那樣:

問題是您要清除包含所有托管實體的整個會話,從而使它們分離。

Hibernate批處理文檔指出,應使用ScrollableResults (可解決這些問題)執行批更新,但是在這種情況下,我必須先獲取所有數據,然后再處理它,因為實體計算可能取決於已經計算的實體。 例如,計算實體3可能需要為實體1和實體2計算的數據。

對於這種情況,最好使用Session#attach(entity) (如代碼所示),使用Session#flush()而不使用Session#clear()還是有更好的解決方案?

問題是您要清除包含所有托管實體的整個會話,從而使它們分離。

如果僅使用部分數據,請確保僅獲取它們,然后可以輕松清除整個會話並獲取下一批並進行相同的計算。

關於LazyInitializationException的文章只是為了澄清它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM