Gaps在JPA @GeneratedValue与PostgreSQL生成的序列值中

时间:2014-04-01 13:19:47

标签: java sql hibernate postgresql jpa

对于我的桌面应用程序,我使用JavaFX,Spring,JPA + Hibernate和PostgreSQL。目前我遇到了几个问题。

问题:违反PRIMARY KEY约束SQL错误

当我按照以下方式创建实体类(GenerationType为AUTO)时,它工作正常。但是当我创建一个新的数据库并使用sql脚本添加一些测试数据时(如下图所示)并尝试使用我的应用程序插入一些数据,我得到了“违反PRIMARY KEY约束”的SQL错误。这意味着似乎Hibernate尝试生成已经可用的PK值(使用我的测试数据ex 1,2,3等分配)。但是经过5次尝试(超过测试数据最大pk值)就可以了,用6个PK键值开始插入数据。

实体类 - GenerationType为AUTO

@Entity
@Table(name = "devicetype")
public class Devicetype implements Serializable {

    @Id
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;

}

包含初始测试数据的表

Table with initial test data

EntityManager工厂

<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
    <property name="packagesToScan" value="com.core.domain" />
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.PostgresPlusDialect</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.format_sql">false</prop>
            <prop key="hibernate.use_sql_comments">false</prop>
            <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
        </props>
    </property>
</bean>  

问题二:差距在序列值

为了解决错误,我按照以下方式更改了Entity类(使用GenerationType作为SEQUENCE)并完成相同的步骤(使用sql脚本插入初始测试数据并尝试通过应用程序插入数据)。然后插入数据,没有任何异常。现在我的表包含通过脚本和应用程序插入的记录(如下图所示)。但是通过应用程序新添加数据(我在浅蓝色上突出显示)具有非常高的PK值(从184开始而不是从6开始)。这意味着“GenerationType as SEQUENCE”似乎hibernate没有按顺序方式填充ID值(保持一些空白)。当我通过应用程序进一步添加一些数据时,似乎将使用另一个更高的ID值插入数据(不是启动表单214)。这意味着ID似乎没有按顺序递增。

实体类 - GenerationType为SEQUENCE

@Entity
@Table(name = "device_type")
public class DeviceType implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name="my_seq", sequenceName="MY_SEQ", allocationSize=1, initialValue=1)
    @Basic(optional = false)
    @Column(name = "ID")
    private Integer id;
 }

带有间隙的表数据(序列ID) enter image description here

1 个答案:

答案 0 :(得分:2)

这就是序列(以及PostgreSQL SERIAL类型)的行为方式。

如果您手动插入值,则需要update the sequence accordingly。或者,更常见的是,不要手动插入值并让序列执行此操作。

除非你想在每个插件上锁定表并消除任何并发希望,否则差距是不可避免的。我建议不要关心。

记住 - 这些数字并不意味着什么,它们只是一个方便的标识符。

花几分钟阅读这一切是如何运作的:CREATE SEQUENCEALTER SEQUENCE