为了账号安全,请及时绑定邮箱和手机立即绑定

意外的重复键异常

意外的重复键异常

青春有我 2022-06-15 16:41:33
我看到 Spring Boot 2.0.4 + Hibernate 有一种奇怪的行为。我有一个包含随机生成代码的实体。如果已为另一个实体设置了生成的代码,DataIntegrityViolationException则按预期抛出 a。这样,循环可以使用希望不使用的新代码再次尝试。发生这种情况时,循环继续,生成新代码,调用saveAndFlush()再次抛出相同的异常,说明导致问题的原始代码(上一次迭代)已被使用(重复)。但是,我现在正在设置一个新代码,而不是异常提到的那个。我唯一能想到的是 Hibernate 不会从“队列”中删除操作,所以当第二次调用saveAndFlush()发生时,它仍然会尝试执行第一次保存,然后执行新的保存。显然,第一次保存与第一次迭代一样失败。也许我错了,但是这里发生了什么?@Entitypublic 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}@Transactionalpublic 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 不直接执行INSERTor UPDATE,则在提交事务之前发生的刷新期间抛出异常,这并不是我真正想要的。
查看完整描述

2 回答

?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

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

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


查看完整回答
反对 回复 2022-06-15
?
慕容森

TA贡献1853条经验 获得超18个赞

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

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


查看完整回答
反对 回复 2022-06-15
  • 2 回答
  • 0 关注
  • 121 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信