当前位置: 首页 > 知识库问答 >
问题:

Hibernate批处理更新-不更新实体

冯宏恺
2023-03-14

我有一个批处理过程,它正在为一组实体重新计算数据。通过Hibernate从DB获取实体列表:

@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。冬眠LazyInitializationException-无法初始化代理-无会话

在我的第一次尝试中,我试图通过调用session#refresh(entity)insiderecreacteentity(…) -这解决了延迟初始化问题,但#2中的问题仍然存在:

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

因为这还没有解决问题,所以我考虑使用附加(实体)而不是刷新(实体)

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

这似乎奏效了,但我的问题是:为什么这些实体一开始就分离了?

(我正在使用Hibernate 3.6.10)

正如@galovics所解释的:

问题是您正在清除包含所有托管实体的整个会话,从而使它们分离。

Hibernate批次处理作业留档指示应该使用Scrollable结果(解决了这些问题)执行批次更新,但是在这种情况下,我必须在处理它之前获取所有数据,因为实体计算可能依赖于已经计算过的实体。例如,计算实体#3可能需要为实体#1计算的数据

对于这样的情况,使用会话#附加(实体)(如代码所示),使用会话#flush()而不使用会话#Clear()会更好吗?或者有更好的解决方案吗?


共有1个答案

司徒钱青
2023-03-14

问题是您正在清除包含所有托管实体的整个会话,从而使它们分离。

如果只处理部分数据,请确保只提取它们,然后可以轻松地清除整个会话,提取下一批数据并执行相同的计算。

关于LazyInitializationException的文章只是为了澄清一下。

 类似资料:
  • 问题内容: 我有一个dao,它基本上使用hibernate将记录插入到一​​个表中,该dao用标记为注释,并且我有一个服务,该服务会生成其他一些东西,然后调用我的dao。我的服务也标注了使用。 我叫服务循环。我在dao上的插入内容是否可以批量或一个接一个地工作?我如何确定它们可以批量工作?hibernateTransaction Manager是否管理批处理插入? 我正在使用Oracle DB。

  • 问题内容: 对于Java-JDBC API和Oracle数据库,我有一个稍微独特的要求。我将autoCommit设置为默认值,这对于Oracle是正确的,并且我使用的示例与此链接相似。 但是,当我添加说1000批次时,可以说每个批次都是插入的。并且让我们假设大约20条记录违反了某些约束,我希望其余980条变为COMMITTED(并且以后对使用任何其他连接的任何其他查询都可见)到数据库,并忽略20条

  • 问题内容: 当前,我们在数据层中使用JDBC,并计划用hibernate代替它。我是Hibernate的新手,不确定Hibernate如何处理并发。如果我们使用spring进行事务管理,有人可以解释一下我如何处理并发更新:通过hibernate(在内存中进行hibernate的自动版本管理),或者我必须将version列放入数据库中以手动处理并发更新。 问题答案: 无论你是否使用Spring进行事

  • 我需要在我的MySQL数据库中进行批量插入(近10000个)。我正在使用JPA/Hibernate和spring Boot。我从hibernate文档中读到了在hibernate中执行大容量插入/更新,我认为我的代码不能正常工作,因为它顺序地插入hibernate查询,而不是在批处理插入中执行它们。下面是我的代码。我是不是漏掉了什么? 这是我的数据源配置。 我是不是漏掉了什么? 请帮帮忙。

  • 问题内容: 我遇到这样的情况,我想更新一些输入为复选框的数据,我在下面尝试了此代码。数据已保存在数据库中,但数据已保存在另一行中, 例如:我为BirdA选中了红色,黄色和灰色,同时为BirdD选中了黑色和蓝色。在数据库中,BirdA的颜色正确保存,但是第二只鸟的深色和蓝色保存在BirdB上( 应保存在BirdD上 ) 我想解决上面的问题,因此数据应保存在数据库中的正确位置。请在下面检查我的代码:

  • 问题内容: 我知道该主题已经在许多问题上得到了解答,但仍然无法解决。 我只想 在提取 大型xml文件的 某些内容 时 更新progressBar 。我认为在另一个线程中使用耗时的循环就足够了,但是?。我设法得到的是ProgressBar要么根本不显示,要么在关闭之前最后进行更新。 在启动该应用程序附近的某个地方,我有: 在显示和更新带有JProgressBar的JDialog时: 所以我有这个 m