休眠和UUID标识符

介绍

我以前的文章中,我谈到了UUID代理密钥以及用例这些用例比更常见的自动增量标识符更合适。

UUID数据库类型

有几种方法可以表示128位UUID,并且每当有疑问时,我都希望向Stack Exchange寻求专家建议。


由于通常对表标识符建立索引,因此数据库类型越紧凑,索引所需的空间就越少。 从效率最高到最低,这是我们的选择:

  1. 某些数据库( PostgreSQLSQL Server )提供专用的UUID存储类型
  2. 否则,我们可以将这些位存储为字节数组(例如,Oracle中的RAW(16)或标准BINARY(16)类型)
  3. 另外,我们可以使用2个bigint(64位)列,但是复合标识符的效率要比单个列低
  4. 我们可以将十六进制值存储在CHAR(36)列中(例如32个十六进制值和4个破折号),但这将占用最多的空间,因此这是效率最低的替代方法

Hibernate提供了许多标识符策略供您选择,对于UUID标识符,我们有三种选择:

  • 分配的生成器以及应用程序逻辑UUID生成
  • 十六进制“ uuid”字符串生成器
  • 更灵活的“ uuid2”生成器,使我们可以使用java.lang.UUID ,16字节数组或十六进制String值

分配的发电机

分配的生成器允许应用程序逻辑控制实体标识符生成过程。 通过简单地省略标识符生成器定义,Hibernate将考虑分配的标识符。 此示例使用BINARY(16)列类型,因为目标数据库是HSQLDB

@Entity(name = "assignedIdentifier")
public static class AssignedIdentifier {

    @Id
    @Column(columnDefinition = "BINARY(16)")
    private UUID uuid;

    public AssignedIdentifier() {
    }

    public AssignedIdentifier(UUID uuid) {
        this.uuid = uuid;
    }
}

持久实体:

session.persist(new AssignedIdentifier(UUID.randomUUID()));
session.flush();

恰好生成一个INSERT语句:

Query:{[insert into assignedIdentifier (uuid) values (?)][[B@76b0f8c3]}

让我们看看发出合并时会发生什么:

session.merge(new AssignedIdentifier(UUID.randomUUID()));
session.flush();

这次我们同时获得了SELECT和INSERT:

Query:{[select assignedid0_.uuid as uuid1_0_0_ from assignedIdentifier assignedid0_ where assignedid0_.uuid=?][[B@23e9436c]} 
Query:{[insert into assignedIdentifier (uuid) values (?)][[B@2b37d486]}

persist方法接受一个临时实体,并将其附加到当前的Hibernate会话中。 如果已经存在一个连接的实体,或者如果当前的实体是分离的,我们将得到一个异常。

合并操作会将当前对象状态复制到现有的持久实体(如果有)中。 此操作对临时实体和分离实体均有效,但对于临时实体持久化要比合并操作有效得多。

对于分配的标识符,合并将始终需要进行选择,因为Hibernate无法知道是否已经存在具有相同标识符的持久化实体。 对于其他标识符生成器,​​Hibernate会寻找一个空标识符,以判断该实体是否处于过渡状态。

这就是为什么Spring Data SimpleJpaRepository#save(S实体)方法不是使用分配的标识符的实体的最佳选择的原因:

@Transactional
public <S extends T> S save(S entity) {
    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

对于分配的标识符,此方法将始终选择合并而不是持久化,因此您将为每个新插入的实体同时获得SELECT和INSERT。

UUID生成器

这次我们不会自己分配标识符,而是让Hibernate代表我们生成它。 当遇到一个空标识符时,Hibernate假定一个临时实体,为其生成一个新的标识符值。 这次,合并操作将不需要在插入过渡实体之前进行选择查询。

UUIDHexGenerator

UUID十六进制生成器是最早的UUID标识符生成器,​​它以“ uuid”类型注册。 它可以生成具有以下模式的32个十六进制UUID字符串值(也可以使用分隔符):8 {sep} 8 {sep} 4 {sep} 8 {sep} 4。

此生成器不符合IETF RFC 4122 ,它使用8-4-4-4-12数字表示。

@Entity(name = "uuidIdentifier")
public static class UUIDIdentifier {

    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid")
    @Column(columnDefinition = "CHAR(32)")
    @Id
    private String uuidHex;
}

持久化或合并临时实体:

session.persist(new UUIDIdentifier());
session.flush();
session.merge(new UUIDIdentifier());
session.flush();

每个操作生成一个INSERT语句:

Query:{[insert into uuidIdentifier (uuidHex) values (?)][2c929c6646f02fda0146f02fdbfa0000]} 
Query:{[insert into uuidIdentifier (uuidHex) values (?)][2c929c6646f02fda0146f02fdbfc0001]}

您可以检出发送到SQL INSERT查询的字符串参数值。

UUIDGenerator

较新的UUID生成器符合IETF RFC 4122(变体2),并提供可插拔生成策略。 它以“ uuid2”类型注册,并且提供了更大的类型范围供您选择:

@Entity(name = "uuid2Identifier")
public static class UUID2Identifier {

    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    @Column(columnDefinition = "BINARY(16)")
    @Id
    private UUID uuid;
}

持久化或合并临时实体:

session.persist(new UUID2Identifier());
session.flush();
session.merge(new UUID2Identifier());
session.flush();

每个操作生成一个INSERT语句:

Query:{[insert into uuid2Identifier (uuid) values (?)][[B@68240bb]} 
Query:{[insert into uuid2Identifier (uuid) values (?)][[B@577c3bfa]}

当我们配置@Id列定义时,此SQL INSERT查询正在使用字节数组。

翻译自: https://www.javacodegeeks.com/2014/07/hibernate-and-uuid-identifiers.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值