由于先前尝试(但未持久)错误插入,休眠选择(JpaRepository 动态查找)失败

Posted

技术标签:

【中文标题】由于先前尝试(但未持久)错误插入,休眠选择(JpaRepository 动态查找)失败【英文标题】:Hibernate select (JpaRepository dynamic find) fails due to previously attempted (but not persisted) bad insert 【发布时间】:2016-05-20 02:40:59 【问题描述】:

我有一个引用 JpaRepository 的 Service 类。

@Autowired
private MyRepository MyRepository;

MyRepository 定义为

public interface MyRepository extends JpaRepository<MyObject, String>

    List<MyObject> findMyObjectByThisIdAndThatId(String thisId, String thatId);
    // other other find method

我的代码在一个自定义 Spring Batch Writer 的循环中,它对一些预读数据进行一些处理,然后保存 MyObject 的实例。

相关的伪循环是:

for each dataset containing data for new/updated MyObject
    1. query DB for existing instance of MyObject by uniquely identifying data
    2. create new MyObject instance or modify returned MyObject instance
    3. `JpaRepository.save(MyObject)` (could be insert or update)

我在第一个数据集中有一些垃圾,这导致尝试写入数据库 (#4) 数据是错误的,即获取值“状态”的 2 字符状态字段。 (这将被修复但尚未解决,因为可能会出现保存失败,因此代码需要处理它。)

显然数据库不喜欢这样。但是,JpaRepository.save(或 saveAndFlush)似乎在没有推送到数据库的情况下返回。

当我回到外观顶部并再次运行 #2 时,该 DB 查询失败,但我应该在上一次循环迭代中得到异常。

我正在使用 Spring Boot、Spring Batch、mysql、JPA(和 JdbcTemplate,它在部分循环中使用,但不在此读/写中)。 Tomcat 只是在运行,因为我需要 Actuator。

我在 application.properties 中有 spring.datasource.auto-commit=true

由于某种原因,在后续读取之前保存不会进入数据库。

但最奇怪的是,对于每个后续循环迭代,读取都会失败,并在相同数据上出现异常。所以由于某种原因,“事务”(因为我没有使用事务而松散地使用)被缓冲,并且在第一次错误保存之后,故障永远不会被刷新,并且会不断返回到所有后续读取。

请帮忙!!!我该如何解决?!我确定这是我缺少的一些简单的东西。

新信息 似乎在我的find 方法调用期间,SessionImpl.list() 调用了SessionImpl.autoFlushIfRequired(),它间接尝试执行和刷新所有未执行的事务。 EntityInsertAction 不会在此处重新创建(因为它是一个旧的 EntityInsertAction 正在重新执行),因此每次后续选择都会引发相同的插入异常。

如何让失败的插入被丢弃,以便后续操作不受前一个操作状态的支配?

【问题讨论】:

【参考方案1】:

这称为auto-flushing,并在official Hibernate documentation 中(请参阅第一段中的第一个要点)进行了(简要)描述。 Hibernate 自动刷新Session 的原因是为了确保SELECT 查询使用最新的数据,这需要缓存在Session 中的内存中更改被持久化。

避免这种情况的唯一(可靠)方法是在for 循环之前从您的伪代码执行第1 步。这将确保for 循环仅执行INSERTUPDATE 语句,而不执行SELECT 语句。

如果数据量太大,可以批量处理输入数据,比如一次500条记录。

【讨论】:

您的编辑不会改变解释。您仍在一个循环中查询数据库,您也在其中对数据进行更改。正如我所说,您必须在循环之前查询数据库,并且只能在循环内进行更改。任何尝试在循环中执行这两项操作都会导致 Hibernate Session 自动刷新。 如果您不同意,请发布实际代码而不是伪代码。我还认为,如果您只是发布实际代码,您可以大大缩短您的帖子。

以上是关于由于先前尝试(但未持久)错误插入,休眠选择(JpaRepository 动态查找)失败的主要内容,如果未能解决你的问题,请参考以下文章

JPA - 更新二进制数据

Tomcat 7 SEVERE:在 pom 中将 spring-data-jpa 添加到依赖项后,由于先前的错误,上下文 [] 启动失败

休眠 JPA 错误

如何使用休眠将mysql与Java连接?例外:没有名为 org.hibernate.tutorial_jpa 的 EntityManager 的持久性提供程序 [关闭]

JPA合并与持久化[重复]

Spring数据JPA-休眠多对多关系在链接实体表中插入null