【问题标题】:Unexpected duplicate key exception意外的重复键异常
【发布时间】:2019-02-12 18:58:30
【问题描述】:

我发现 Spring Boot 2.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 不直接执行INSERTUPDATE,则会在提交事务之前发生的刷新期间引发异常,这并不是我真正想要的。

【问题讨论】:

    标签: java hibernate spring-boot


    【解决方案1】:

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

    因此,请将重试逻辑放在事务边界之外,或者如果您需要保持完整性(全部或全部保存),请先检查它是否存在以避免抛出异常。

    【讨论】:

      【解决方案2】:

      如果您调试代码并查看持久性上下文的状态,您可能会得到答案。没错,hibernate 维护着一个队列,即事务期间进行的所有查询都将在提交/刷新时运行。

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

      【讨论】:

        猜你喜欢
        • 2023-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多