如何在Hibernate和MySQL中使用UUID
对于分布式数据库,自动增量ID不能正常工作。相反,我们应该使用UUID。让我们考虑一下UUID的优点和缺点,以及在Hibernate和MySQL中如何使用。
UUID简介
优点
通用唯一标识符(UUID)在每个数据库中都是全球唯一的!
这带来了以下优点:
-
轻松合并来自不同数据库的条目。没有冲突的主键。
-
轻松复制和同步分布式数据库。
-
我们可以在任何地方生成UUID。因此,不需要往返数据库,因为我们可以在应用程序层中生成UUID。这也简化了测试,并允许轻松- 批量插入彼此引用的实体。
-
可以猜测自动增量ID,这可能导致安全问题(例如,在URL中使用ID参数并刮掉所有内容)。
缺点
但是,也存在一些缺点:
- UUID增加了值和索引所需的大小。单个UUID需要16个字节。相反,普通的int键只需要4个字节。
- 他们使临时查询更加笨拙(见下文)。
- REST资源中的UUID会增加有效负载大小。
创建一个表
UUID使用VARCHAR(36)数据类型并不是一个好主意。相反,我们应该使用 BINARY(16)。这最小化了所需的值大小和索引大小。但是,这会使查询更复杂一些。
CREATE TABLE product (
`id` BINARY(16) NOT NULL primary key
,`name` varchar(64)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Hibernate集成
Hibernate支持 java.util.UUID
和UUID生成。因此,Hibernate本身在客户端生成UUID。只需将以下注释添加到您的实体类:
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(columnDefinition = "BINARY(16)")
private UUID id;
有用的SQL代码片段
我们可以使用uuid()生成的UUID。
SELECT uuid(); /*dbe07414-49d1-11e6-b7a7-0242ac140002*/
插入
请注意,uuid()返回带有破折号的UUID。我们必须使用replace()
删除它们才能插入。此外,我们必须使用unhex()
将十六进制(人类可读)UUID转换为其二进制表示。现在它适合BINARY(16)。
INSERT INTO product VALUES(
unhex(replace(uuid(), '-', ''))
, "car"
);
读取
使用hex()
的UUID字节转换回其十六进制表示。
SELECT id, name FROM product;
/* BLOB, 'car' */
SELECT hex(id), name FROM product;
/* 'BFF641BA9F3A4584A1BA53824E7AB3B9', 'car' */
让我们使用查询某个UUID unhex()。
SELECT hex(id), name FROM product
WHERE id = unhex('BFF641BA9F3A4584A1BA53824E7AB3B9');
/* or if you have a UUID with dashes: */
SELECT hex(id), name FROM product
WHERE id = unhex(replace("2b08e375-275d-473e-910d-32700e34b61a", '-', ''));
Demo
在GitHub上,我创建了一个简单的Spring Boot + Hibernate/JPA 项目来演示UUID的实际运行情况。