所以我们的项目使用PostgreSQL数据库,我们使用JPA来操作数据库.

在进行小的更改后,我们的主键值描述为:

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Basic(optional = false)
@NotNull
@Column(name = "idwebuser", nullable = false)
private Integer idwebuser;

问题是,现在的应用程序并不灵活,因为当我们直接(使用SQL或其他工具)修改数据库而不是通过Java应用程序时,生成的值低于实际的数据库ID值,因此我们在创建新实体时会出错.

JPA是否有可能让数据库自动生成ID,然后在创建过程后获取它?

EDIT

a short note on the answer There was a little lie from my side because we've used a PG Admin -> View first 100 Rows and edited rows from there instead of using select. ANYWAY, it turns out that this editor somehow skips the process of updating the ID and so even in DB when we write a proper INSERT it is EXECUTED with improper ID! So it was basically more a problem of the editor we used than the database and application...

现在,它甚至可以使用@GeneratedValue(strategy=GenerationType.IDENTITY)

推荐答案

根据表格定义:

CREATE TABLE webuser(
    idwebuser SERIAL PRIMARY KEY,
    ...
)

使用映射:

@Entity
@Table(name="webuser")
class Webuser {

    @Id
    @SequenceGenerator(name="webuser_idwebuser_seq",
                       sequenceName="webuser_idwebuser_seq",
                       allocationSize=1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
                    generator="webuser_idwebuser_seq")
    @Column(name = "idwebuser", updatable=false)
    private Integer id;

    // ....

}

命名tablename_columname_seq是PostgreSQL对SERIAL的默认序列命名,我建议您坚持使用它.

如果您需要Hibernate与数据库的其他客户端合作,那么allocationSize=1是很重要的.

请注意,如果事务回滚,该序列将有"间隙".由于各种原因,事务可能会回滚.应用程序的设计应该能够应对这种情况.

  • 不要假设任何id n都有id n-1n+1
  • 永远不要假设id n是在id小于n之前或id大于n之后添加或提交的.如果你真的很小心如何使用序列,你可以做到这一点,但你永远不应该try ;而是在表中记录一个时间戳.
  • 永远不要在ID上加或减.比较它们是否相等.

参见PostgreSQL documentation for sequencesthe serial data types.

他们解释说,上面的表格定义基本上是一种快捷方式:

CREATE SEQUENCE idwebuser_id_seq;
CREATE TABLE webuser(
    idwebuser integer primary key default nextval('idwebuser_id_seq'),
    ...
)
ALTER SEQUENCE idwebuser_id_seq OWNED BY webuser.idwebuser;

... 这应该有助于解释为什么我们添加了@SequenceGenerator个注释来描述序列.


如果你真的必须有一个无间隙序列(例如支票或发票编号),请参见gapless sequences,但认真地说,避免使用这种设计,never将其用作主键.


Note:如果表定义如下所示:

CREATE TABLE webuser(
    idwebuser integer primary key,
    ...
)

您可以使用(unsafe, do not use)插入:

INSERT INTO webuser(idwebuser, ...) VALUES ( 
    (SELECT max(idwebuser) FROM webuser)+1, ...
);

或(unsafe, never do this):

INSERT INTO webuser(idwebuser, ...) VALUES ( 
    (SELECT count(idwebuser) FROM webuser), ...
);

然后you're doing it wrong和应该切换到序列(如上所示)或使用锁定计数器表的correct无间隙序列实现(同样,请参见上文和谷歌中的"无间隙序列postgresql").如果数据库中存在多个连接,上述两种方法都会出错.

Postgresql相关问答推荐

转换失败:(—122.763091,49.04676)转换为地理(位置)""

多克.波斯格雷斯.PgAdmin4

在Ubuntu 18.04 Bionic上安装PostgreSQL(已删除回购)

PostgreSQL无效语法

我应该如何更新热门表?

未更改表上的 Postgres 环绕预防

TimescaleDB 连续聚合:如何存储连续聚合结果

PostgreSQL TIMESTAMPTZ 不适用于 SpringBoot Java Query

Java - 日期保存为前一天

psql中set、\set和\pset的区别

PostgreSQL ORDER BY 问题 - 自然排序

使用 try/except 与 psycopg2 或with closing?

MAC OS X 上的 Postgres 权限被拒绝

Postgresql SERIAL 的工作方式是否不同?

错误:must be owner of language plpgsql

PGAdmin 编辑数据

如果 PostgreSQL count(*) 总是很慢,如何对复杂查询进行分页?

在 postgresql 中获取上个月的数据

学习 PL/pgSQL 的好资源?

如何更改 PostgreSQL 中的 REFERENCES?