【问题标题】:Repository.findAll() returning capitalized UUIDs?Repository.findAll() 返回大写的 UUID?
【发布时间】:2019-01-03 22:50:37
【问题描述】:

关于 Java Spring Data JPA 存储库和我正在使用的具有唯一标识符字段(PK 字段,尽管它是 PK 的事实并不相关)的 SQL Server 表,我遇到了一些奇怪的问题问题)。

我遇到的问题是,当我将新项目插入此表时,UUID 以小写形式返回。当我在表格上执行“findOne”(使用 Spring Data pre-2.0)时,即使“findOne”参数为大写,它也会以小写形式返回。但是,当我在此表上执行“findAll”时,ID 都以大写形式返回。我希望能够做这样的事情来进行测试:

String id = repository.save(...).getField();
List<String> data = repository.findAll().map(d -> d.getField());
assertThat(data.contains(id));

问题是第一行会返回一个小写的ID,第二行会返回一个大写的ID列表,所以第三行会失败。

至于对 UUID 使用字符串,我知道这不是推荐的做法;但是,当我不这样做时(当我使用 UUID 类型时),我遇到了一个完全不同的问题,超出了这个问题的范围。如果推荐的答案是“不要对 UUID 使用字符串”,那么我可以将其作为一个单独的问题提出。

简表定义:

CREATE TABLE [dbo].[TABLE](
    [ID] [uniqueidentifier] NOT NULL,
    <...>
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[TABLE] ADD  CONSTRAINT [DF_TABLE_ID]  DEFAULT (newid()) FOR [ID]
GO

以及实体定义:

@Entity
@Table(name = "TABLE")
public class DataEntity {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    @Column(name = "ID", updatable = false, nullable = false, unique = true)
    private String id;
    <...>
}

【问题讨论】:

  • 如果您确实对 UUID 使用字符串,那么您肯定必须使用数据库在 SELECT 中为您提供的 INSERT 格式。我不知道你的 ORM 在这里做什么,但是 SQL 会隐式地将 UNIQUEIDENTIFIERS 转换为所有大写的字符串类型,并将小写或混合大小写的字符串隐式转换为 UNIQUEIDENTIFIER。所以全大写是唯一可以往返的格式。
  • 能否分享一下实体和表的定义?我不清楚UUIDs 的票价是多少,Strings 或 DB 等价物是什么。另外:你是如何生成 UUID 的?
  • @DavidBrowne-Microsoft UUID 由 Hibernate(Spring Boot 使用的 DB 交互框架)自动生成。它们以小写形式生成,尽管正如您所说的那样确实以大写形式存储。您评论中奇怪的部分是,当我通过 Hibernate(使用 repository.findOne)执行 SELECT 时,我将 UUID 恢复为小写;只有当我执行 repository.findAll 时,我才会得到大写。
  • @JensSchauder 我已将表和实体定义的简要描述添加到 OP。
  • 要么你没有,要么我看到了所有内容的缓存版本。我看到的唯一编辑是更改的标签。

标签: sql-server hibernate spring-data-jpa uuid


【解决方案1】:

为什么不在比较之前将所有字符串转换为相同的大小写(这无关紧要)?

不过,这似乎并不理想;比较两个 36 个字符长的字符串将比 16 字节数字花费更多时间(并且处理它们将占用更多空间),并且由于数据库(您希望)将它们存储为二进制,因此您需要额外的转换成本到那种效率较低的形式。哦,即使对于相同的字节数,字符串比较也会变慢,因为它不知道它们是固定长度的,它可能必须一次比较一个字节,而不是使用更广泛的比较。

【讨论】:

  • 在撰写此问题时,设计限制之一是不允许转换为字符串,很遗憾。
【解决方案2】:

使用生成器,您指定您在应用程序端生成 UUID,并将它们发送到数据库,并以一种有效的格式存储它们,这种格式肯定不包含有关大小写的任何信息,因为它只是一个数字.

我怀疑您在选择中看到的差异可能来自会话缓存,并且与您使用的方法没有太大关系:如果在缓存中找到实体,则返回它,如果它刚刚保存它包含 Hibernator 生成的 UUID 格式(因此大小写取决于 Hibernate 中的 toString() 方法)。

如果在缓存中找不到实体,则返回它,因为它来自数据库,这很可能取决于您使用的 JDBC 驱动程序中的实现细节。

那么如何解决这个问题:

简单的方法:Use guid as the generator。它将命中数据库,因此 UUID 将始终采用数据库提供的格式。如果性能很关键,这可能不是一个可行的选择。 注意:我在当前文档中找不到这个生成器,不知道它是否已被弃用。

困难的方法:查找或创建一个 UUID 生成器,该生成器以数据库返回的确切格式创建 UUID。

UUID 的生成似乎有惊人的回旋余地,所以这里有一个链接列表供进一步阅读:

Vlad Mihalcea 关于 UUID:https://vladmihalcea.com/hibernate-and-uuid-identifiers/

有点类似的问题:Different representation of UUID in Java Hibernate and SQL Server

Hibernate documentation about UUID 的当前版本。

【讨论】:

    猜你喜欢
    • 2022-07-15
    • 1970-01-01
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多