Java 意外的重复密钥异常

Java 意外的重复密钥异常,java,hibernate,spring-boot,Java,Hibernate,Spring Boot,我在SpringBoot2.0.4+Hibernate上看到了一个奇怪的行为 我有一个包含随机生成代码的实体。如果已为另一个实体设置生成的代码,则会按预期引发DataIntegrityViolationException。通过这种方式,循环可以使用新代码重试,希望不会使用新代码。发生这种情况时,循环将继续,生成一个新代码,对saveAndFlush()的调用再次抛出相同的异常,表示导致问题的原始代码(上一次迭代)已被使用(重复)。但是,我现在正在设置一个新代码,而不是异常提到的代码 我能想到的唯

我在SpringBoot2.0.4+Hibernate上看到了一个奇怪的行为

我有一个包含随机生成代码的实体。如果已为另一个实体设置生成的代码,则会按预期引发
DataIntegrityViolationException
。通过这种方式,循环可以使用新代码重试,希望不会使用新代码。发生这种情况时,循环将继续,生成一个新代码,对
saveAndFlush()
的调用再次抛出相同的异常,表示导致问题的原始代码(上一次迭代)已被使用(重复)。但是,我现在正在设置一个新代码,而不是异常提到的代码

我能想到的唯一一件事是Hibernate不会从“队列”中删除该操作,因此当第二次调用
saveAndFlush()
时,它仍会尝试执行第一次保存,然后执行新的保存。显然,在第一次迭代中,第一次保存失败。也许我错了,但这到底是怎么回事

@Entity
public class Entity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private int code;

    public void setCode(int code) {
        this.code = code;
    }

    //Other properties

}

@Transactional
public void myFunction() {
    boolean saved = false;
    do {
        int code = /* Randomly generated code */;
        if(entity == null) {
            entity = new Entity(code, /* other properties */);
        } else {
            entity.setCode(code);
        }

        try {
            entity = myRepository.saveAndFlush(entity);
            saved = true;
        } catch (DataIntegrityViolationException e) {
            /* Ignore so that we can try again */
        }
    } while(!saved);
}

编辑:


如果我将
saveAndFlush()
替换为
save()
,问题就会消失。我在某个地方看到,如果还调用了
flush()
,则在上次保存失败后进行保存可能会有问题。这正是我的情况。然而,我不明白为什么这是一个问题。调用
saveAndFlush()
而不是
save()
的唯一原因是捕获重复密钥异常。使用
save()
,如果Hibernate不直接执行
INSERT
UPDATE
,则在提交事务之前发生的刷新过程中会引发异常,这不是我真正想要的。如果调试代码并查看持久性上下文的状态,您可能会得到答案。您是对的,hibernate维护一个排序队列,即在事务期间进行的所有查询都将在提交/刷新时运行


请发布调试时获得的持久性上下文的值。

在这种情况下,您需要重新启动事务,因为错误已绑定到事务上下文/会话

因此,请将重试逻辑置于事务边界之外,或者如果需要保持完整性(保存全部或不保存任何内容),请首先检查它是否存在,以避免引发异常