Spring Data R2 DBC PostgreSQL未使用UUID @Id保存新记录

s2j5cfk0  于 2023-03-22  发布在  PostgreSQL
关注(0)|答案(6)|浏览(170)

我有一个简单的实体,由两个UUID组成:

@Table("library")
public class LibraryDao {
    @Id
    private UUID id;
    @NonNull
    private UUID ownerId;
}

我在PostgreSQL中有一个对应的表:

CREATE TABLE IF NOT EXISTS library (id UUID PRIMARY KEY, owner_id UUID NOT NULL);

我正在使用正确的R2DBC驱动程序(io.r2dbc:r2dbc-postgresqlorg.postgresql:postgresql)。
在这一点上,一切正常。我的应用程序运行。但是...
因为PostgreSQL没有(至少根据文档)UUID的自动生成功能,所以我在创建新的LibraryDao示例时设置id。
但是,当我在Repository中调用save方法时,我得到一个异常:Failed to update table [library]. Row with Id [0ed4d7c0-871a-4473-8997-4c9c1ec67a00] does not exist.
看起来save被解释为update,如果不存在,则没有回退到insert
我该如何在数据库中插入新记录?

vhipe2zx

vhipe2zx1#

除了PostgreSQL文档,还有一种方法可以使用pgcrypto扩展(用于v4 UUID)自动生成UUID。(基于使用pgAdmin GUI的过程。)
在查询工具中:

  • select * from pg_extension并检查pgcrypto是否未列出。
  • create extension pgcrypto安装它;它是默认安装的。

然后,使用将列定义更改为... id UUID PRIMARY KEY DEFAULT gen_random_uuid(), ...
而且很管用。

bvjxkvbb

bvjxkvbb2#

然而,除了我的answer关于使用R2 DBC DatabaseClient进行插入之外,还有一种方法可以使用React式存储库的save方法-通过使用Persistable接口,这是非常直接的。
它的isNew方法可以使用实体的version属性来实现,或者通过添加一个新的专用属性(类似于boolean isAlreadyPersisted)来实现,该属性可以在调用save()之前显式设置。

628mspwn

628mspwn3#

由于R2 DBC还没有自动生成UUID,并且Spring内部使用的工具有自己的机制,可以防止向DB发送null(因此无法使用触发器来完成这项工作)-也许这里的最佳解决方案是使用Java(UUID.randomUUID();)生成UUID,并在将实体发送到DB之前将其放入实体中。

编辑-具体解决方案:

您的解决方案的一个小问题是必须修改DB安装。
在意识到上述插入问题后,我放弃了使用存储库save方法来执行此操作,并切换到使用R2 DBC DatabaseClient的“手动”解决方案:

dbClient.sql("insert into product_price(id, product_id, price) values(:id, :product_id, :price)")
      .bind("id", UUID.randomUUID())
      .bind("product_id", 1)
      .bind("price", 10.0)
      .fetch()
      .one()
      .subscribe();

下面是DatabaseClient,它是从ConnectionFactory配置的,并允许接受命名参数:

@Bean
public DatabaseClient dbClient(ConnectionFactory connectionFactory) {
    return DatabaseClient.builder()
            .connectionFactory(connectionFactory)
            .namedParameters(true)
            .build();
}

ConnectionFactory也是我在扩展AbstractR2dbcConfiguration的配置类中公开的一个易于定制的Bean。
希望reactive repository中的save()能够得到改进,使其表现得像其他spring-data repository中的对应物一样。

h22fl7wq

h22fl7wq4#

因为您已经提供了@Id。库需要确定该行是新的还是应该存在。
Mark Paluch已经在spring-data-r2 dbc issues board上回答了这个问题。请参阅#275以获取更多参考。此外,您还可以从#49中找到有用的信息。

nimxete2

nimxete25#

我已经阅读和研究了上面的内容,不仅在这里,但是,它并没有解决问题。这是不够的。
您的字段(主键)必须有一个列类型,例如serial,这样数据库在插入记录时,会自动增加记录id

没有这个,所有其他食谱将无法工作

pxy2qtax

pxy2qtax6#

UUID可以自动生成,如果您自己生成它,Hibernate会看到具有id的实体并尝试更新它。
要自动生成uuid,只需在字段上使用以下注解:

@GeneratedValue(generator = "UUID")
@GenericGenerator(
    name = "UUID",
    strategy = "org.hibernate.id.UUIDGenerator",
)

来源:https://thorben-janssen.com/generate-uuids-primary-keys-hibernate/

相关问题