Repository 中的 deleteAll() 随机导致 ConstraintViolationException

isA*_*Don 5 java spring hibernate spring-data

我有对 API 执行 CRUD 操作的测试。在每次测试之前,都会重新创建 API 中的测试数据。意思是删除数据库中的所有数据并重新插入测试数据。

public void initDatabase() {
    answerTranslationRepository.deleteAll();
    answerRepository.deleteAll();
    userRepository.deleteAll();
    //....

    Answer answer = new Answer();
    AnswerTranslation answerTranslation = new AnswerTranslation("test", answer);
    //....

    answerTranslationRepository.save(answerTranslation);
    answerRepository.save(answer);  
}
Run Code Online (Sandbox Code Playgroud)

运行所有测试在大多数情况下都有效,但有时调用answerRepository.deleteAll();会失败,并显示:

2018-04-01 09:09:49.069 ERROR 14260 --- [           main] o.h.i.ExceptionMapperStandardImpl        : HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [fkco3o4hxryohduthxj2vgnuhxs]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:259)
    //..... 
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:536)
    ... 54 more
Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on table "answer" violates foreign key constraint "fkco3o4hxryohduthxj2vgnuhxs" on table "answer_translation"
  Detail: Key (id)=(ab54d53a-cd55-428a-aac7-40b20ead86de) is still referenced from table "answer_translation".
Run Code Online (Sandbox Code Playgroud)

答案与答案翻译有以下关系:

@OneToMany(mappedBy = "answer", cascade = CascadeType.ALL)
private List<AnswerTranslation> translations = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)

答案翻译为答案:

@ManyToOne
private Answer answer;
Run Code Online (Sandbox Code Playgroud)

如果没有答案,答案翻译就不可能存在。

我不明白为什么answerRepository.deleteAll(); 有时answerTranslationRepository会失败并显示错误,因为该方法应该在尝试删除答案之前从第一个数据中删除数据。

Rea*_*hed 7

这是使用 JPA Hibernate 时的常见问题。数据库查询执行不是从代码中按顺序转换的。您只需flush()在从数据库表中删除条目后调用即可。

所以修改后的函数应该是这样的。

public void initDatabase() {
    answerTranslationRepository.deleteAll();
    answerTranslationRepository.flush();

    answerRepository.deleteAll();
    answerRepository.flush();

    userRepository.deleteAll();
    userRepository.flush();
    //....

    Answer answer = new Answer();
    AnswerTranslation answerTranslation = new AnswerTranslation("test", answer);
    //....

    answerTranslationRepository.save(answerTranslation);
    answerRepository.save(answer);  
}
Run Code Online (Sandbox Code Playgroud)

你可以看看这个答案,里面有很好的解释。