简体   繁体   English

休眠批处理更新-实体未更新

[英]Hibernate Batch Update - Entities are not updated

I have a batch process which is recalculating data for a set of entities. 我有一个批处理过程,它正在重新计算一组实体的数据。 The entities list is fetched from DB by hibernate: 实体列表是通过休眠从数据库中获取的:

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

When the process runs it looks like some entities are becoming detached, causing two symptoms: 该过程运行时,看起来某些实体变得分离,从而导致两个症状:

  1. When trying to fetch lazy data I get an exception: org.hibernate.LazyInitializationException - could not initialize proxy - no Session . 尝试获取惰性数据时,出现异常: org.hibernate.LazyInitializationException - could not initialize proxy - no Session
  2. When no lazy load is needed - only the first 10 records are updated in DB, even though flushIfNeeded(...) is working ok. 当不需要惰性加载时-即使flushIfNeeded(...)工作正常,DB中仅更新前10条记录。

On my first try, I tried to resolve it by calling session#refresh(entity) inside recalculateEntity(...) - this solved the lazy initialization issue, but the issue in #2 still occurred: 在我的第一次尝试中,我尝试通过在recalculateEntity(...)内调用session#refresh(entity)来解决该问题-这解决了延迟初始化问题,但#2中的问题仍然发生:

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

Since this haven't solved the issue I thought about using attach(entity) instead of refresh(entity) : 既然这还没有解决问题,我考虑过要使用attach(entity)而不是refresh(entity)

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

This seems to work, but my question is: Why did these entities get detached in the first place? 这似乎可行,但是我的问题是: 为什么这些实体首先被分离?

(I'm using Hibernate 3.6.10) (我正在使用Hibernate 3.6.10)


Update 更新

As @galovics explained: 正如@galovics解释的那样:

The problem is that you are clearing the whole session which holds all your managed entities, making them detached. 问题是您要清除包含所有托管实体的整个会话,从而使它们分离。

Hibernate batch processing documentation indicates that batch updates should be performed using ScrollableResults (which resolves these issues), but in this case I have to fetch all the data before processing it, as an entity calculation might depend on entities that were already calcualted. Hibernate批处理文档指出,应使用ScrollableResults (可解决这些问题)执行批更新,但是在这种情况下,我必须先获取所有数据,然后再处理它,因为实体计算可能取决于已经计算的实体。 For example, calculating Entity#3 might require data calculated for Entity#1 & Entity#2. 例如,计算实体3可能需要为实体1和实体2计算的数据。

For a case like this, would it be better to use Session#attach(entity) (as shown in the code), using Session#flush() without using Session#clear() or is there a better solution? 对于这种情况,最好使用Session#attach(entity) (如代码所示),使用Session#flush()而不使用Session#clear()还是有更好的解决方案?

The problem is that you are clearing the whole session which holds all your managed entities, making them detached. 问题是您要清除包含所有托管实体的整个会话,从而使它们分离。

If you are working with just part of the data, make sure you only fetch them, and then you can easily clear the whole session and fetch the next batch and do the same calculation. 如果仅使用部分数据,请确保仅获取它们,然后可以轻松清除整个会话并获取下一批并进行相同的计算。

Article on LazyInitializationException just to clarify it. 关于LazyInitializationException的文章只是为了澄清它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM