存储库中的deleteAll()随机导致ConstraintViolationException

时间:2018-04-01 07:32:45

标签: 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);  
}

运行所有测试的时间大多数但是时不时调用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".

答案与AnswerTranslation有以下关系:

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

回答翻译答案:

@ManyToOne
private Answer answer;

如果没有答案,则不能存在AnswerTranslation。

我无法理解为什么answerRepository.deleteAll(); 有时因显示的错误而失败,因为该方法应首先从answerTranslationRepository删除数据,然后再尝试删除答案。

1 个答案:

答案 0 :(得分:2)

当您使用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);  
}

你可以在this answer看看这里有一个很好的解释。