【问题标题】:Hibernate @ElementCollection Map with @Audited create duplicate key violation on updateHibernate @ElementCollection Map with @Audited 在更新时创建重复键冲突
【发布时间】:2017-05-20 19:49:53
【问题描述】:

我在使用休眠映射和审计时遇到了问题。 我的带有映射的 java 类:

@Entiy
@Audited
@Table(name = "farm_detail")
public class FarmDetail {
   @Id
   private Long id;

    @ElementCollection
    @MapKeyColumn(name = "field_id")
    @Column(name = "remark")
    @CollectionTable(name = "farm_detail_remark", joinColumns =    @JoinColumn(name = "farm_detail_id"))
    private Map<String, String> fieldRemarks = new HashMap<>();
   // Getter, Setter, etc
}

farm_detail_remarkfarm_detial_remark_aud表的sql定义:

db=# \d farm_detail_remark
          Table "public.farm_detail_remark"
     Column     |          Type          | Modifiers 
----------------+------------------------+-----------
 farm_detail_id | bigint                 | not null
 field_id       | character varying(255) | not null
 remark         | character varying      | not null
Indexes:
    "farm_detail_remark_pkey" PRIMARY KEY, btree (farm_detail_id, field_id)
Foreign-key constraints:
    "farm_detail_remark_farm_detail_id_fkey" FOREIGN KEY (farm_detail_id) REFERENCES farm_detail(id)

db=# \d farm_detail_remark_aud
        Table "public.farm_detail_remark_aud"
     Column     |          Type          | Modifiers 
----------------+------------------------+-----------
 rev            | integer                | not null
 revtype        | smallint               | 
 farm_detail_id | bigint                 | not null
 field_id       | character varying(255) | not null
 remark         | character varying      | 
Indexes:
    "farm_detail_remark_aud_pkey" PRIMARY KEY, btree (rev, farm_detail_id, field_id)
Foreign-key constraints:
    "farm_detail_remark_aud_rev_fkey" FOREIGN KEY (rev) REFERENCES revinfo(rev)

如果我想更新 fieldRemarks 集合的任何条目,我会在 farm_detail_remark_aud 表上收到重复键错误。通过打开 sql 日志,我发现 hibernate 尝试在 aud 表中插入两个条目:

Hibernate: 
    /* insert farm_detail_remark_AUD
        */ insert 
        into
            farm_detail_remark_aud
            (revtype, rev, farm_detail_id, remark, field_id) 
        values
            (?, ?, ?, ?, ?)
21:20:58.188 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [1] as [INTEGER] - [0]
21:20:58.188 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [2] as [INTEGER] - [1057]
21:20:58.188 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [3] as [BIGINT] - [110]
21:20:58.188 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [4] as [VARCHAR] - [Old remark]
21:20:58.188 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [5] as [VARCHAR] - [152]

和(这里只有参数绑定):

21:20:58.193 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [1] as [INTEGER] - [2]
21:20:58.194 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [2] as [INTEGER] - [1057]
21:20:58.194 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [3] as [BIGINT] - [110]
21:20:58.194 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [4] as [VARCHAR] - [new remark]
21:20:58.194 [main] TRACE o.h.t.d.s.BasicBinder - binding parameter [5] as [VARCHAR] - [152]

有没有办法解决这个问题,而无需为备注创建额外的实体?

我使用的是 Spring Boot 1.5.7 附带的休眠 5.0.12。数据库是postgresql 9.5.6。

【问题讨论】:

  • 因此,您实际上是在事务中通过键更新映射的值,导致与映射键的旧值相关的 REVTYPE=2 (DEL) 和与映射相关的 REVTYPE=0 (ADD)键的新值。

标签: hibernate jpa hibernate-mapping hibernate-envers


【解决方案1】:

我针对 5.0.12 和 5.2.10 对此进行了测试,在这两种情况下,为您的映射生成的表架构与您提供的不同。这可能是您最近升级过 Hibernate 的旧版应用程序吗?

例如,在 H2 上,我在测试中创建的表显示如下:

create table farm_detail_remark_AUD (
  REV integer not null, 
  field_detail_id integer not null, 
  remark varchar(255) not null, 
  field_id varchar(255) not null, 
  REVTYPE tinyint, 
  primary key (REV, field_detail_id, remark, field_id)
)

因此,对于您的方案,不会生成重复的主键,因为 remark 列包含在主键索引中,从而避免了您面临的问题。

【讨论】:

  • 它不是遗留的,但我不让 hibernate 生成数据库模式。但如果你迷路了,这是一个让 hibernate 执行此操作的好技巧。稍后我将检查 hibernate-envers 在每个修订版的此类“重复”条目上返回什么。你知道这是在哪里记录的吗?
  • 我们没有任何具体的地方来描述或记录基于给定映射的架构。我们经常依赖hibernate-tools,用户调用它来生成架构脚本,他们要么选择运行其中的一部分,要么至少验证他们手动创建的内容是否正确。
  • 另一种选择是使用您的实体映射针对虚拟数据库或 H2 实例启动您的应用程序,并查看日志以查看作为替代方式执行的 DDL 语句。
猜你喜欢
  • 2016-11-10
  • 2011-06-24
  • 1970-01-01
  • 2020-09-11
  • 1970-01-01
  • 1970-01-01
  • 2021-03-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多