Spring Data JPA生成的UUID字段为空。

3

我有一个名为Booking的实体,它具有一个生成的id字段,我将其用作主键。目前这个方案运行良好。我希望添加另一个字段uuid,这将作为REST API中资源标识符。我使用Postgres数据库并设置该字段自动生成:

uuid character varying(36) not null default uuid_generate_v1mc()

创建时,DB可以很好地生成id和uuid,但在Java代码中,uuid字段为null。我的实体如下:

@Entity
public class Booking {

    @Id
    @SequenceGenerator(name="booking_id_seq", sequenceName="booking_id_seq", allocationSize=1)
    @GeneratedValue(strategy= GenerationType.IDENTITY, generator = "booking_id_seq")
    private Long id;

    @Column(nullable = false)
    private String uuid;
(...)
}

我做错了什么?

跟进:感谢所有人的评论和答案。看起来我有两个选择,要么从数据库重新加载实体以生成由数据库生成的UUID,要么在代码中自己生成UUID。哪一个更好?我猜后者的性能更高,但还有其他需要考虑的因素吗?


2
只有 @Id 字段会自动与数据库同步,其他生成的字段不会。您需要从数据库重新加载实体。 - M. Deinum
1
仅生成id。uuid不是id,因此不会自动生成,您必须设置一个值,因为该字段不可为空。 - Bilal BBB
2个回答

5
你可以在实体类中使用@PrePersist来进行填充。
@PrePersist
public void autofill() {
    this.setUuid(UUID.randomUUID().toString());
}

我为您的问题创建了一个示例项目: https://github.com/zz-chen/Sample-spring-data-jpa-generate-uuid 您可以使用以下命令运行它。
gradle bootRun

"你将会收到类似于这样的一条消息。"
2017年6月26日11:12:16.118 INFO 78681 --- [main] hello.Application:使用findOne(1L)找到客户:2017年6月26日11:12:16.119 INFO 78681 --- [main] hello.Application:-------------------------------- 2017年6月26日11:12:16.120 INFO 78681 --- [main] hello.Application:客户[id = 1,firstName ='Jack',lastName ='Bauer',uuid ='44969325-c31f-4b8e-96d6-a59ff9b845b6'] 2017年6月26日11:12:16.122 INFO 78681 --- [main] hello.Application:使用findByLastName('Bauer')找到客户:2017年6月26日11:12:16.122 INFO 78681 --- [main] hello.Application:-------------------------------------------- 2017年6月26日11:12:16.158 INFO 78681 --- [main] hello.Application:客户[id = 1,firstName ='Jack',lastName ='Bauer',uuid ='44969325-c31f-4b8e-96d6-a59ff9b845b6'],客户[id = 3,firstName ='Kim',lastName ='Bauer',uuid ='0cef24ad-ce97-4c79-b8a4-69ff575326fb']
通过这条消息,我们可以确认 UUID 字段运行得非常完美!!!

谢谢,我最终采用了你的解决方案,因为我认为使用PrePersist更加优雅。 - vargen_

1
你只需要在实体的字段中添加以下内容:
import java.util.UUID;

@Column(unique = true, name = "uuid", nullable = false)
private String uuid = UUID.randomUUID().toString().toUpperCase();

我不认为这是一个好的解决方案。如果我们从数据库中读取数据,当JPA读取每个记录并将其序列化为对象时,它所做的是使用默认空构造函数创建对象,然后会无必要地执行uuid = UUID.randomUUID().toString().toUpperCase(),尽管该值将被JPA序列化程序重写为来自数据库的值,但第一次在处理器消耗方面并不便宜。 - Mariano Ruiz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接