【问题标题】:Hibernate Jpa - constraint violation exception on Primary Key(Sequence)Hibernate Jpa - 主键(序列)上的约束违规异常
【发布时间】:2019-04-29 13:19:17
【问题描述】:

我在我的应用程序中使用 Hibernate JPA。我有一个具有主键(序列)的表。服务将记录插入到该表中。

版本:Oracle 12c

方言:org.hibernate.dialect.Oracle10gDialect

问题:

我们在负载测试期间遇到问题(SEQUENCE Key 上的唯一约束违规)。

问题:

  1. 此问题并非一直存在。但仅在负载测试期间。有人可以检查并帮助使用线程安全生成器吗?

  2. 是 DB 端序列定义问题还是 Java 端?

数据库序列:

CREATE SEQUENCE MY_SEQ    
START WITH 1
INCREMENT BY 1
NOMINVALUE
NOMAXVALUE
CACHE 30
NOORDER;

CREATE TABLE MY_TABLE    (  
    MY_PRIMARY_KEY INT default MY_SEQ.nextval NOT NULL,
    VALUE_COL VARCHAR2(10) NULL       
);

实体:

public class MyTableEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "MY_PRIMARY_KEY")
    @GenericGenerator(
        name = "mySequenceGenerator",
        strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
                @Parameter(name = "sequence_name", value = "SEQUENCE MY_SEQ"),
                @Parameter(name = "increment_size", value = "1")
        }
    )
    @GeneratedValue(generator = "mySequenceGenerator")
    private long myPrimaryKey;

    @Column(name = "VALUE")
    private String value;

}

【问题讨论】:

  • 首先,@Parameter(name = "sequence_name", value = "SEQUENCE MY_SEQ"), - 此参数包含两个单独的名称:SEQUENCE + MY_SEQ。第二 - 根据Documentation of SequenceStyleGenerator 没有名为sequence_name 的参数,但有SEQUENCE_PARAM - Indicates the name of the sequence (or table) to use.,所以我认为你应该尝试:@Parameter(name = "sequence_param", value = "MY_SEQ"),
  • 请发布您的 Oracle 版本和使用的 Hybernate 方言。可能的解释是您在INSERT 中传递了一个PK 值,它用sequence 覆盖了DEFAULT 子句。
  • @Marmite Bomber,我更新了 Oracle 版本和使用的 Hibernate 方言
  • 你自己回答了这个问题。 Oracle10gDialect 不支持带有序列的列 DEFAULT,从 Oracle 12 开始可用。IMO 您的 DB 表定义与 Hibernate 类不对应。使用 Hibernate 自动重新创建表或升级您的方言。
  • @krokodilko 的评论似乎也很相关......

标签: spring multithreading oracle hibernate jpa


【解决方案1】:

Oracle 10 方言

对于 Oracle10gDialect 使用此配置

@Id
@Column(name = "MY_PRIMARY_KEY")
@GeneratedValue(strategy=GenerationType.AUTO)
Long myPrimaryKey;

Hibernate 创建一个表和一个序列:

create table MY_TABLE (
MY_PRIMARY_KEY number(19,0) not null, 
VALUE varchar2(255 char), 
primary key (MY_PRIMARY_KEY))

create sequence hibernate_sequence 

在存储时首先获取新的序列 ID,然后在 INSERT 语句中传递它

select hibernate_sequence.nextval from dual
insert into MY_TABLE (VALUE, MY_PRIMARY_KEY) values (?, ?)

Oracle 12 方言

如果您使用原生支持 IDENTITY columnOracle 12,则最好升级到 Oracle12cDialect(请注意,这需要 Hibernate 5.3)

strategy 设置为GenerationType.IDENTITY

@Id
@Column(name = "MY_PRIMARY_KEY", updatable = false, nullable = false)
@GeneratedValue(strategy=GenerationType.IDENTITY)
Long myPrimaryKey;

创建了下表-重要的部分是generated as identity,它提供了独特的velues。 请注意,不需要创建显式sequence,它是内部管理的。

create table MY_TABLE (
MY_PRIMARY_KEY number(19,0) generated as identity, 
VALUE varchar2(255 char), 
primary key (MY_PRIMARY_KEY))

虽然存储在INSERT中没有传递ID,但它由Oracle分配并返回给会话

insert into MY_TABLE (VALUE) values (?) RETURNING MY_PRIMARY_KEY INTO ? 

请注意,与 Oracle 10 不同,您可以节省一次到数据库的往返行程。

【讨论】:

  • 您可以在字典视图select * from ALL_TAB_IDENTITY_COLS;中查看有关隐式创建序列的详细信息
【解决方案2】:

长改长

因为如果你使用 long,它(默认)是 0。不允许生成器更改现有值!

https://docs.oracle.com/javaee/7/api/javax/persistence/GeneratedValue.html

【讨论】:

    猜你喜欢
    • 2020-08-12
    • 2011-04-19
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 2015-09-02
    • 2014-09-28
    相关资源
    最近更新 更多