JPA实体的UUID主键:在多个示例上使用唯一值的安全方法

vfhzx4xs  于 2022-11-14  发布在  其他
关注(0)|答案(2)|浏览(128)

我正在使用SpringBoot、JPA和Hibernate。
我有一个疑问。
对于我的实体,我需要一个UUID作为主键(我希望以“清除模式”(字符串)而不是二进制保存此ID)
我使用的代码是:

@Id
@Column(name = "id")
@Type(type = "uuid-char")
private UUID uuid = UUID.randomUUID();

我的怀疑是这样的:这种方法安全吗?我能确保id始终是唯一的吗?
我知道,使用此代码,UUID将在代码端生成,因此,如果我的服务有多个示例,所有示例都使用相同的DB服务,会发生什么情况?
是否可能有更多示例生成相同的UUID?

zkure5ic

zkure5ic1#

UUID uuid = UUID.randomUUID()
我的怀疑是这样的:这种方法安全吗?我能确保id始终是唯一的吗?
是的,非常安全。
UUID版本4有122位随机生成的数据。这是一个 * 巨大 * 的数字范围。假设你的UUID是用cryptographically-strong random number generator生成的,你对使用随机生成的UUID没有实际的顾虑。
有关详细信息,请参见维基百科上的 * 碰撞 * 部分。
如果你想担心,把你的担心放在那些更有可能发生的事情上。Cosmic rays翻转非EEC memory中的位。(有关此问题,请参见有效的rant by Linus Torvalds。)
就我个人而言,我认为像第1版这样的时空点版本更不用担心碰撞,但其他人对此有争议。无论是第1版还是第4版,我都会睡得很好。
尽管如此,您仍然应该确保编写的代码在冲突面前是健壮的。这不是因为随机生成的重复数据造成的冲突,而是因为人为的可能性造成的冲突,例如代码中的错误将记录两次发送到数据库,或者DBA错误地加载了备份数据两次,等等。

sy5wg1nm

sy5wg1nm2#

我不是冬眠Maven,但是,如果你这样做,一般来说,它应该是可以的,这意味着碰撞的概率很低,但是“如果”有碰撞呢?换句话说,你不能100%确定你“保证避免碰撞”。如果你的系统可以处理碰撞(例如,重新创建一个UUID,假设性能损失可以忽略不计,因为这种情况极少发生),那么当然没有问题。
现在真实的的问题是,是否还有其他的事情可以做呢?嗯,Hibernate能够以一种同样使用机器的IP作为生成参数的方式来生成UUID

@Entity
public class SampleEntity {
 
    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
        name = "UUID",
        strategy = "org.hibernate.id.UUIDGenerator",
        parameters = {
            @Parameter(
                name = "uuid_gen_strategy_class",
                value = "org.hibernate.id.uuid.CustomVersionOneStrategy"
            )
        }
    )
    @Column(name = "id", updatable = false, nullable = false)
    private UUID id;
     
    …
}

有关详细信息,请阅读here示例
当然,最好的方法是让DB来处理ID的生成。您还没有指定使用哪个数据库。例如,Postgresql允许在扩展的帮助下生成UUID键:
例如,读取here
一般来说,使用UUID并不总是一个好主意--在日常生活中很难处理它们,而且一般来说,如果表中有很多行,它们会带来很大的开销。所以你可以考虑使用自动递增序列或其他东西作为主键-- DB可以做到这一点,你不需要费心。

相关问题