Spring 数据 R2DBC PostgreSQL 未使用 UUID @Id 保存新记录
Spring Data R2DBC PostgreSQL not saving new record with UUID @Id
我有一个简单的实体,由两个 UUID 组成:
@Table("library")
public class LibraryDao {
@Id
private UUID id;
@NonNull
private UUID ownerId;
}
我在PostgreSQL中有对应的table:
CREATE TABLE IF NOT EXISTS library (id UUID PRIMARY KEY, owner_id UUID NOT NULL);
我正在使用正确的 R2DBC 驱动程序(io.r2dbc:r2dbc-postgresql
和 org.postgresql:postgresql
)。
至此,一切正常。我的应用程序运行。但是……
因为 PostgreSQL 没有——至少根据文档——没有自动生成 UUID 的功能,所以我在创建新的 LibraryDao
实例时设置了 id。
但是,当我在我的存储库中调用 save
方法时,出现异常:Failed to update table [library]. Row with Id [0ed4d7c0-871a-4473-8997-4c9c1ec67a00] does not exist.
似乎 save
被解释为 update
,如果 insert
不存在,则不会回退到 insert
。
我应该如何将新记录插入我的数据库?
UUID可以是auto-generated,如果你自己生成它 Hibernate看到有id的实体并尝试更新它。
要 auto-generate uuid,只需在您的字段上使用以下注释:
@GeneratedValue(generator = "UUID")
@GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator",
)
来源:https://thorben-janssen.com/generate-uuids-primary-keys-hibernate/
尽管有 PostgreSQL 文档,但有一种方法可以使用 pgcrypto 扩展(对于 v4 UUID)auto-generate UUID。 (基于使用 pgAdmin GUI 的过程。)
在查询工具中:
select * from pg_extension
并检查 pgcrypto 是否未列出。
create extension pgcrypto
安装;它带有默认安装。
然后,将列定义更改为 ... id UUID PRIMARY KEY DEFAULT gen_random_uuid(), ...
而且有效。
由于 R2DBC(还)没有 auto-generation 的 UUID,并且内部使用的工具 Spring 有自己的机制来防止向 DB 发送空值(因此触发器可以完成这项工作' t 被使用) - 也许这里的最佳解决方案是使用 Java (UUID.randomUUID();
) 生成 UUID,并在将实体发送到 DB 之前将它们放入实体中。
编辑 - 具体解决方案:
您的解决方案的一个小问题是必须修改数据库安装。
在意识到所描述的插入问题后,我不再尝试使用存储库 save
方法,而是使用 R2DBC 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
也是一个易于定制的 Bean,我在扩展 AbstractR2dbcConfiguration
.
的配置 class 中公开了它
并且希望反应式存储库中的 save()
将得到改进,使其表现得与其他 spring-data 存储库中的对应物一样。
但是,除了我的 about doing inserts using R2DBC DatabaseClient
, there IS a way to do it using reactive repository's save
method - by using Persistable 界面,它还很漂亮 straight-forward。
它的 isNew
方法可以使用实体的 version
属性来实现,或者通过添加一个可以在调用 [=15 之前显式设置的新的专用属性(类似于 boolean isAlreadyPersisted
)来实现=].
也许还有其他一些我不知道的利用 Persistable
的方法。
我有一个简单的实体,由两个 UUID 组成:
@Table("library")
public class LibraryDao {
@Id
private UUID id;
@NonNull
private UUID ownerId;
}
我在PostgreSQL中有对应的table:
CREATE TABLE IF NOT EXISTS library (id UUID PRIMARY KEY, owner_id UUID NOT NULL);
我正在使用正确的 R2DBC 驱动程序(io.r2dbc:r2dbc-postgresql
和 org.postgresql:postgresql
)。
至此,一切正常。我的应用程序运行。但是……
因为 PostgreSQL 没有——至少根据文档——没有自动生成 UUID 的功能,所以我在创建新的 LibraryDao
实例时设置了 id。
但是,当我在我的存储库中调用 save
方法时,出现异常:Failed to update table [library]. Row with Id [0ed4d7c0-871a-4473-8997-4c9c1ec67a00] does not exist.
似乎 save
被解释为 update
,如果 insert
不存在,则不会回退到 insert
。
我应该如何将新记录插入我的数据库?
UUID可以是auto-generated,如果你自己生成它 Hibernate看到有id的实体并尝试更新它。
要 auto-generate uuid,只需在您的字段上使用以下注释:
@GeneratedValue(generator = "UUID")
@GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator",
)
来源:https://thorben-janssen.com/generate-uuids-primary-keys-hibernate/
尽管有 PostgreSQL 文档,但有一种方法可以使用 pgcrypto 扩展(对于 v4 UUID)auto-generate UUID。 (基于使用 pgAdmin GUI 的过程。)
在查询工具中:
select * from pg_extension
并检查 pgcrypto 是否未列出。create extension pgcrypto
安装;它带有默认安装。
然后,将列定义更改为 ... id UUID PRIMARY KEY DEFAULT gen_random_uuid(), ...
而且有效。
由于 R2DBC(还)没有 auto-generation 的 UUID,并且内部使用的工具 Spring 有自己的机制来防止向 DB 发送空值(因此触发器可以完成这项工作' t 被使用) - 也许这里的最佳解决方案是使用 Java (UUID.randomUUID();
) 生成 UUID,并在将实体发送到 DB 之前将它们放入实体中。
编辑 - 具体解决方案:
您的解决方案的一个小问题是必须修改数据库安装。
在意识到所描述的插入问题后,我不再尝试使用存储库 save
方法,而是使用 R2DBC 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
也是一个易于定制的 Bean,我在扩展 AbstractR2dbcConfiguration
.
并且希望反应式存储库中的 save()
将得到改进,使其表现得与其他 spring-data 存储库中的对应物一样。
但是,除了我的 DatabaseClient
, there IS a way to do it using reactive repository's save
method - by using Persistable 界面,它还很漂亮 straight-forward。
它的 isNew
方法可以使用实体的 version
属性来实现,或者通过添加一个可以在调用 [=15 之前显式设置的新的专用属性(类似于 boolean isAlreadyPersisted
)来实现=].
也许还有其他一些我不知道的利用 Persistable
的方法。