【问题标题】:EclipseLink and Sequence Generator PreallocationEclipseLink 和序列生成器预分配
【发布时间】:2013-08-30 17:00:42
【问题描述】:

我有一个无法解决的问题。在休眠状态下,我对以下内容没有任何问题:

@GeneratedValue( strategy = GenerationType.AUTO, generator = "email-seq-gen" )
@SequenceGenerator( name="email-seq-gen", sequenceName="EMAIL_SEQ_GEN", allocationSize=500 )

然后在我的 schema.ddl 我有这个:

CREATE SEQUENCE EMAIL_SEQ_GEN START 1 INCREMENT 500;

这里没什么可看的。一切都按预期工作。但是,如果我将提供程序切换到 EclipseLink,我会收到此错误:

The sequence named [EMAIL_SEQ_GEN] is setup incorrectly.  Its increment does not match its pre-allocation size.

当然,如果初始值为 1 并且它应该等于 allocationSize,那么我当然会四处搜索有关 EclipseLink 创建负数的信息。

所以,好吧,添加“initialValue=500”并将我的 DDL 脚本更新为“START 500”可以解决此问题,但现在我的编号从 500 开始,而不是 1。有什么用?这是一个 EclipseLink 错误还是我不理解的东西。我想生成从 1 开始的序列,并具有针对实体调整的分配大小(在本例中为 500)。我将如何使用 EclipseLink 做到这一点?

谢谢!

问这个问题的另一种方法是......鉴于这个 DDL:

CREATE SEQUENCE EMAIL_SEQ_GEN START 1 INCREMENT 500;

注释我的实体以将其与 EclipseLink 一起使用的正确方法是什么?

如果我让 EclipseLink 生成我的 DDL,那么:

@GeneratedValue( strategy = GenerationType.AUTO, generator = "email-seq-gen" )
@SequenceGenerator( name="email-seq-gen", sequenceName="EMAIL_SEQ_GEN", initialValue=1, allocationSize=500 )

会生成这个:

CREATE SEQUENCE EMAIL_SEQ_GEN INCREMENT BY 500 START WITH 500;

这意味着使用 EclipseLink 创建具有“START WITH 1”的 DDL 是不可能的。

【问题讨论】:

  • 如果你走另一个方向(让 EclipseLink 从你的实体生成 DDL)它会生成什么?
  • 我编辑了原始帖子以添加对您问题的答案。

标签: hibernate jpa eclipselink


【解决方案1】:

默认情况下,带有 @SequenceGenerator 注释的实体使用 initialValue=1 和 alocationSize=50。

public @interface SequenceGenerator {
    /** 
     * (Optional) The value from which the sequence object 
     * is to start generating.
     */
    int initialValue() default 1;

    /**
     * (Optional) The amount to increment by when allocating 
     * sequence numbers from the sequence.
     */
    int allocationSize() default 50;
}

EclipseLink 似乎使用以下公式计算了“顺序”实体 ID:

entityId = initialValue - allocationSize + INCREMENT_BY

或者在使用 DDL 的情况下:

entityId = START_WITH - allocationSize + INCREMENT_BY

回到您的具体案例:


@SequenceGenerator( 
    name="email-seq-gen", 
    sequenceName="EMAIL_SEQ_GEN", 
    allocationSize=500
) // initialValue=1 (default)

CREATE SEQUENCE EMAIL_SEQ_GEN START WITH 1 INCREMENT BY 500;

生产

entityId = 1 - 500 + 1 = -500 // EclipseLink error

@SequenceGenerator( 
    name="email-seq-gen", 
    sequenceName="EMAIL_SEQ_GEN", 
    initialValue=1, 
    allocationSize=500 )

CREATE SEQUENCE EMAIL_SEQ_GEN START WITH 1 INCREMENT BY 500;

生产

entityId = 1 - 500 + 1 = -500 // EclipseLink error

@SequenceGenerator( 
    name="email-seq-gen", 
    sequenceName="EMAIL_SEQ_GEN", 
    initialValue=500, 
    allocationSize=500
)

CREATE SEQUENCE EMAIL_SEQ_GEN START WITH 500 INCREMENT BY 500;

生产

entityId = 500 - 500 + 500 = 500 // fine, but inappropriate
entityId = 500 - 500 + 1000 = 1000 // incremented by 500
entityId = 500 - 500 + 1500 = 1500 // incremented by 500
...

为满足您的要求,应使用以下一种:

@SequenceGenerator( 
    name="email-seq-gen", 
    sequenceName="EMAIL_SEQ_GEN", 
    allocationSize=500 
) // initialValue=1 (default) but 'START WITH'=500

CREATE SEQUENCE EMAIL_SEQ_GEN START WITH 500 INCREMENT BY 1;

生产

entityId = 500 - 500 + 1 = 1
entityId = 500 - 500 + 2 = 2
entityId = 500 - 500 + 3 = 3
...

可以使用以下 SQL command 从基础数据库中删除现有序列:

DROP SEQUENCE email_seq_gen RESTRICT;

希望对你有帮助。

【讨论】:

  • 很高兴知道如何删除/删除创建的序列。我尝试了几种方法,但都没有奏效。
  • @burseaner:我添加了一个删除现有序列的命令。
  • 创建增量为 1 的序列是错误的。 EclipseLink 每个分配批次只调用一次序列(在这种情况下,每 500 个实体在同一事务中添加一次)。因此增量必须等于 500。是的,当分配批次小于 500 时,数字将被跳过,但由于序列调用较少,这是您为效率付出的代价。要查看发生的错误,请添加两个实体,然后终止 Java 程序,然后添加另一个实体。由于 ID 重复,将发生 java.sql.SQLIntegrityConstraintViolationException。
【解决方案2】:

你的序列应该从 500 而不是 1 开始。如果你从 1 开始,那么第一个 nextval 只会给你 1 个 id 而不是 500。

否则在设置完序列后调用nextval,所以它到达501。

错误是警告还是错误?如果你只是忽略它,它仍然有效吗?

【讨论】:

  • 这有什么意义?如果我编写代码来池身份,我会得到 1、501、1001 等等。这也是我从Hibernate得到的?如果 EclipseLink 不是这种情况,并且(通过谷歌搜索)似乎很多人对此有疑问,为什么他们不直接修复这个算法?
【解决方案3】:

我可以通过在模式生成中添加一句话来解决这个问题:RESTART

实体定义

@GeneratedValue(strategy=GenerationType.SEQUENCE, generator=Secuences.PROFILES_SEQ)
@SequenceGenerator(name=Secuences.PROFILES_SEQ, sequenceName=Secuences.PROFILES_SEQ, allocationSize=25)
@Column( name = "id" )
private Long internalId;

SQL 架构初始化

-- create sequence
CREATE SEQUENCE PROFILES_SEQ START WITH 1;

-- use sequence to set values in column
UPDATE public.cc_user_profile SET id = nextval('PROFILES_SEQ');

-- update sequence
ALTER SEQUENCE PROFILES_SEQ INCREMENT BY 25 START WITH 25;
ALTER SEQUENCE PROFILES_SEQ RESTART;

希望它可以帮助某人。

【讨论】:

    猜你喜欢
    • 2013-11-18
    • 2013-01-13
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 2016-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多