一个关于 JPA 下,表主键生成 UUID 的问题

查看 16|回复 0
作者:Koril   
项目使用 Spring Data JPA + MySQL ,碰到了主键 id 使用 UUID 的一个问题。
如果只是单纯的自动生成 UUID ,那好像挺简单的:
@Entity
@Table(name = "t_user")
public class User {
    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
        name = "UUID",
        strategy = "org.hibernate.id.UUIDHexGenerator",
    )
    @Column(name = "id")
    private String id;
    @Column(name = "name")
    private String name;
}
这样子使用@GenericGenerator的 Entity ,调用继承了JpaRepository[U]的UserRepository的 save()方法,就可以插入一个记录,并且这条记录的 UUID 的值是框架自动生成的。
现在,碰到一个问题:我希望 User 的 id 如果没有被赋值,那么由框架去自动生成一个 UUID ,否则,使用我自己赋值的 UUID 插入到数据库中,换句话说,如果前端传来了一个特定的 UUID ,并且该 id 不存在于数据库中,就以该 id 为主键值插入数据。
但是经过我自己的测试,一旦注解了@GeneratedValue,框架似乎直接忽略了我给 entity 赋值的 UUID ,而是重新生成一个新的值,插入数据库。
我想到两种方案:
[ol]

  • 最简单粗暴的,去掉@GeneratedValue和@GenericGenerator注解,每一次调用save()的时候手动赋值一个 UUID ( User user = new User(); user.setId(generateUUID())),也就是说,完全由自己控制主键的生成。

  • 写一个自定义的主键生成器,替代org.hibernate.id.UUIDHexGenerator,我写的代码如下:
    [/ol]
    package cn.korilweb.demojpa.generator;
    // 省略 import
    public class CustomUUIDGenerator extends UUIDHexGenerator {
        @Override
        public Serializable generate(SharedSessionContractImplementor session, Object obj) {
            try {
                // 获取 entity id 字段的值
                Field field = obj.getClass().getDeclaredField("id");
                field.setAccessible(true);
                String id = (String) field.get(obj);
                // 如果已经设置,直接返回
                if (Objects.nonNull(id)) {
                    return id;
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            // 没有 id ,自动生成随机的 UUID
            String sep = "";
            return format( getIP() ) + sep
                    + format( getJVM() ) + sep
                    + format( getHiTime() ) + sep
                    + format( getLoTime() ) + sep
                    + format( getCount() );
        }
    }
    然后 User 类的主键注解中的 strategy 参数改成:
    @Id
        @GeneratedValue(generator = "UUID")
        @GenericGenerator(
                name = "UUID",
                strategy = "cn.korilweb.demojpa.generator.CustomUUIDGenerator"
        )
        @Column(name = "id")
        private String id;
    第二种方式奏效了,但我想问问有没有其他的方式呢?
    另外,我的问题和 Stack Overflow 上的这个问题很相似: https://stackoverflow.com/questions/45102456/how-to-set-autogenerated-id-manually
    请问,有没有同学碰到过这种情况,有什么更好的解决方案呢?感谢!
  • 您需要登录后才可以回帖 登录 | 立即注册

    返回顶部