基于My Spring Data(JPA / Hibernate)的应用程序在Postgres中持久化新实体时会增加负载以下异常: org.postgresql.util.PSQLException:错误:重复键值违反了唯一约束“hibernate_sequences_pkey”
id的策略定义如下:
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "ID")
public Long getId() {
return id;
}
我知道这种策略不是Postgres的完美解决方案,但是上面例外的原因是什么?
使用Apache Camel路由生成负载,并且拆分器在多个线程上并行运行插入。
答案 0 :(得分:3)
经过一些测试后,确实问题确实是由strategy = GenerationType.TABLE
引起的。随着对strategy = GenerationType.SEQUENCE
的更改,上面描述的问题已经消失了。
@Id
@SequenceGenerator(name = Consts.VEHICLE_ATTR_ID_SEQ,
sequenceName = Consts.VEHICLE_ATTR_ID_SEQ,
allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = Consts.VEHICLE_ATTR_ID_SEQ)
@Column(name = "ID", updatable = false)
public Long getId() {
return id;
}
答案 1 :(得分:0)
从Hibernate 4迁移到5.3.1(Wildfly 14.0.1)时,我还遇到了与“重复键值违反唯一约束” hibernate_sequences_pkey”错误消息有关的问题。在研究Hibernate 5.3.1的源代码后,我可以使用strategy = GenerationType.TABLE
来消除错误(我也知道这种策略不是完美的解决方案)。主要问题在TableGenerator类中。要解决该问题,您还应该使用GenericGenerator批注例如:
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = TableGenerator.DEF_TABLE)
@GenericGenerator(name = TableGenerator.DEF_TABLE, strategy
= "org.hibernate.id.enhanced.TableGenerator", parameters = {
@Parameter(name = TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITY, value = "true")})
@Column(name="id")
private Integer id;
将TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITY
参数设置为true值(因为默认情况下它具有false值,在这种情况下,Hibernate将在hibernate_sequences表中使用“默认”段名称而不是表名称)。
您还应该将hibernate.model.generator_name_as_sequence_name
属性设置为false值,以仅具有一个hibernate_sequences表,否则,Hibernate将使用生成器名称作为序列表的名称(根据https://github.com/hibernate/hibernate-orm/commit/9a75fa8d979185b6014a814bf3ffd09e32143939#diff-936141a440957cd8a9c4a93a744e92a0的更改)。另外(但不是必需),您还可以将hibernate.id.generator.stored_last_used
属性设置为假值(更改https://github.com/hibernate/hibernate-orm/commit/9af565510064635dba7e48087ab4e8f5ef439f0d),因为:
为了符合JPA规范,该值存储在 表中的Hibernate 5.3由
javax.persistence.TableGenerator
是最后生成的值。 以前的Hibernate版本将下一个值存储为 使用。为了向后兼容新设置,
hibernate.id.generator.stored_last_used
被介绍为 让您有机会回到旧的Hibernate行为。 迁移到5.3并使用@TableGenerator的现有应用程序具有 将hibernate.id.generator.stored_last_used
设置为false