在 Spring MVC + Hibernate 中自动生成唯一的随机字符串

aem*_*nal 5 java uuid spring hibernate jpa

背景

我正在使用 Spring MVC (Framework v4.0.6.RELEASE, JPA v1.6.2.RELEASE) 和 Hibernate (Core v4.3.6.FINAL, JPA API v2.1) 编写一个项目。在我的项目中,有名为“项目”的实体。这些项目中的每一个都有其唯一的、自动生成的 ID 作为主键。此 ID 由以下代码生成:

@Id
@Column(name = "project_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long projectId;
Run Code Online (Sandbox Code Playgroud)

此代码按预期工作并自动创建唯一 ID。

问题

这些项目中的每一个都应该有一个随机的、唯一的1 'secret' String,就像 Facebook、Twitter 等 API 提供商分配的那样。因此,为了实现这一点,我尝试使用以下代码,根据 Hibernate 文档:

@Column(name = "project_secret", nullable = false, unique = true)
@GenericGenerator(name = "uuid-gen", strategy = "uuid")
@GeneratedValue(generator = "uuid-gen")
private String projectSecret;
Run Code Online (Sandbox Code Playgroud)

但是,每当我尝试创建一个新的项目实体时,都会遇到一个org.springframework.dao.DataIntegrityViolationException根本原因:

@Id
@Column(name = "project_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long projectId;
Run Code Online (Sandbox Code Playgroud)

这应该由 Hibernate 在创建时自动生成,必须是随机且唯一的1。一个 128 位的 UUID 对我来说就足够了(32 个字符,不带破折号),我读到 Hibernate 有一个 UUID 生成器,所以这就是我打算使用的。

更多信息

在搜索了几个小时之后,我并没有按照我想要的方式解决。我找到了一种可能的解决方案,其中包括:

@PrePersist
private void generateSecret(){
    this.setProjectSecret(UUID.randomUUID().toString());
}
Run Code Online (Sandbox Code Playgroud)

在 Project 实体类中。当这个方法被插入(并且@GenericGenerator&@GeneratedValue标签被移除)时,项目秘密被正确生成和插入;系统按预期工作;不会抛出任何异常。但是,(我相信)这不能确保唯一性2,并且只会在插入重复的秘密时导致异常。我想确保唯一性,最好用内置的 Hibernate 生成器来解决这个问题。

(笔记)

  1. 我实际上不确定是否应该强制执行唯一性。我想每个秘密都是独一无二的(理论上)可以创建一个额外的安全层,这让我:
  2. 我意识到 UUID 冲突的概率非常低,因此 UUID 生成确保了概率意义上的唯一性,但我可以(或应该)确定它吗?

小智 4

我以前遇到过这样的问题,过了一段时间我意识到是我的数据库表导致了问题。这可能与您遇到的问题相同...

对于您的project_id,请确保在数据库中创建该列时使用以下内容

GENERATED ALWAYS AS IDENTITY
Run Code Online (Sandbox Code Playgroud)

我希望这是同样的问题,并且这会对您有所帮助。还建议使用 uuid2 作为您的策略。

请参阅此处... http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#d0e5294

编辑

在意识到project_secret不是@id字段之后,答案是hibernate不支持除@id字段之外的任何列上生成的值。有关更多详细信息,请参阅此处:Hibernate JPA 序列(非 Id)