news 2026/8/27 14:25:30

UUIDv1秒变v6的位运算魔法:uuid-creator TimeOrderedCodec源码剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UUIDv1秒变v6的位运算魔法:uuid-creator TimeOrderedCodec源码剖析

UUIDv1秒变v6的位运算魔法:uuid-creator TimeOrderedCodec源码剖析

【免费下载链接】uuid-creatorUUID Creator is a Java library for generating Universally Unique Identifiers. It generates all standard identifiers from UUIDv1 to UUIDv7. It also provides an alternative to the classic JDK's UUID (alt.GUID), many codecs (codec.*) and several utilities (util.*).项目地址: https://gitcode.com/gh_mirrors/uu/uuid-creator

uuid-creator 是一个开源 Java 库,可生成 UUIDv1 到 UUIDv7 全部标准标识符。本文带你剖析它的 TimeOrderedCodec 源码——仅凭几行位运算,就能把老式 UUIDv1 秒变时间可排序的 UUIDv6,无需任何字符串拼接或第三方依赖。

为什么要把 UUIDv1 转成 UUIDv6?

先搞清楚痛点。UUIDv1 的时间戳被"打散"存放在三个互不相邻的字段里(time_low、time_mid、time_high),导致按字符串排序时,先后生成的 ID 在字典序上是乱序的

这对数据库很不友好:

  • B+ 树写入碎片化:主键随机散落,页分裂频繁,写入性能差
  • 范围查询低效:想按时间取"最近 100 条",索引帮不上忙
  • 缓存命中率低:新记录无法追加在索引末尾

而 UUIDv6 的魔法在于:把 60 位时间戳重排成一个连续的大端整数,字符串字典序 ≈ 时间先后序。这正是 TimeOrderedCodec 要完成的唯一任务。

核心原理:v1 与 v6 的位布局对比

UUID 的 128 位分为高 64 位(msb)和低 64 位(lsb)。TimeOrderedCodec 只动 msb,lsb(时钟序列 + 48 位节点 ID)原样保留:

位段(msb 64位)UUIDv1 布局UUIDv6 布局
bit 63~48time_high(12位)time_high(12位)
bit 47~32time_mid(16位)time_mid(16位)
bit 31~16time_low(16位)time_mid 续… version + time_low 高位
bit 15~12version = 0001version = 0110
bit 11~0time_low 低12位… time_high 高位time_low 低12位

一句话总结转换逻辑:

v1 → v6:把打散的时间戳重新拼成连续整数,版本号从 1 改成 6。v6 → v1:原路拆散回三个字段,版本号改回 1。

源码剖析:3 个十六进制常数就是全部魔法

源码文件位于src/main/java/com/github/f4b6a3/uuid/codec/other/TimeOrderedCodec.java,整个类不到 100 行。

正向转换:v1 秒变 v6

encode方法的核心只有 4 行(约第 62~70 行):

long timestamp = UuidUtil.getTimestamp(uuid); long msb = ((timestamp & 0x0ffffffffffff000L) << 4) // | (timestamp & 0x0000000000000fffL) // | 0x0000000000006000L; // set version 6 long lsb = uuid.getLeastSignificantBits(); return new UUID(msb, lsb);

逐行拆解这 3 个"魔数":

  1. timestamp & 0x0ffffffffffff000L—— 取 60 位时间戳的高 52 位(砍掉最低 12 位)
  2. << 4—— 整体左移 4 位,把版本号的 4 个"坑位"腾出来
  3. | (timestamp & 0xfff)—— 把刚才砍掉的低 12 位补到最末尾
  4. | 0x6000—— 在 bit 15~12 写入0110,宣告"我是 UUIDv6"

妙处在于:左移 + 低位补回,等于把 60 位时间戳无损地"折叠"成一个大端排列——高位在前、低位在后,字典序排序即时间排序。全程没有任何循环和字符串操作,纯位运算,纳秒级完成。

注意时间戳不是直接读出来的,而是委托给src/main/java/com/github/f4b6a3/uuid/util/UuidUtil.java中的getTimestamp()(约第 272 行),它会按 UUID 版本选择正确的拆位策略。

反向转换:v6 还原 v1

decode方法(约第 81~102 行)就是把"折叠"的动作原样展开:

long timeHigh = (timestamp & 0x0fff_0000_00000000L) >>> 48; // 拆出 12 位高位 long timeMid = (timestamp & 0x0000_ffff_00000000L) >>> 16; // 拆出 16 位中段 long timeLow = (timestamp & 0x0000_0000_ffffffffL) << 32; // 拆出 32 位低位 long version = 0x0000000000001000L; // Set version 1

每个"掩码 + 移位"组合,把 v6 连续时间戳中对应的字段搬回 v1 的原始位置,最后或上0x1000把版本号改回 1。由于 encode/decode 是严格互逆的,往返转换零信息损失。

动手实践:一行代码完成转换

// v1 → v6 UUID uuid1 = UuidCreator.getTimeBased(); UUID uuid6 = new TimeOrderedCodec().encode(uuid1); // v6 → v1(可无限往返) UUID back = new TimeOrderedCodec().decode(uuid6);

类中还提供了单例TimeOrderedCodec.INSTANCE,生产环境推荐复用它避免重复 new。如果不想手动转换,也可以直接用门面 APIUuidCreator.getTimeOrdered()一步生成 v6(底层工厂在src/main/java/com/github/f4b6a3/uuid/factory/standard/TimeOrderedFactory.java)。

测试怎么保证正确?

配套的src/test/java/com/github/f4b6a3/uuid/codec/other/TimeOrderedCodecTest.java用 100 次循环做了三重断言:

测试点验证目标
isTimeOrdered(uuid6)产物确实是合法的 v6
时间戳相等转换不丢时间精度
decode(encode(v1)) == v1往返转换完全可逆

总结

  • TimeOrderedCodec 用3 个掩码 + 移位 + 或运算完成了 v1 与 v6 的互转,是位运算在 ID 设计中的教科书级应用
  • 核心收益:ID 天然按时间有序,显著提升 B+ 树数据库的写入与范围查询性能
  • 源码仅 ~100 行且依赖极简,非常适合通读学习——建议结合UuidUtilgetTimestamp一起看

掌握这 4 行核心代码后,你甚至可以在任何语言里复现这套"时间有序化"技巧。

【免费下载链接】uuid-creatorUUID Creator is a Java library for generating Universally Unique Identifiers. It generates all standard identifiers from UUIDv1 to UUIDv7. It also provides an alternative to the classic JDK's UUID (alt.GUID), many codecs (codec.*) and several utilities (util.*).项目地址: https://gitcode.com/gh_mirrors/uu/uuid-creator

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/27 14:23:21

极简语言编年史:milliForth、sectorForth 与 sectorLISP 深度对比

极简语言编年史&#xff1a;milliForth、sectorForth 与 sectorLISP 深度对比 【免费下载链接】milliForth A FORTH in 340 bytes — the smallest real programming language ever as of yet. 项目地址: https://gitcode.com/gh_mirrors/mi/milliForth 在 340 字节的极…

作者头像 李华
网站建设 2026/8/27 14:22:09

大模型应用开发全流程:从初始构思到实验、效果评估和产品化!

简介 本文提供了构建大型语言模型原生应用的全面指南&#xff0c;强调了标准化流程的重要性。文章介绍了LLM工程师所需的多领域技能&#xff0c;以及自下而上和自上而下两种开发方法。重点阐述了实验思维、提示工程、模型选择等优化策略&#xff0c;以及如何通过健全性测试确保…

作者头像 李华
网站建设 2026/8/27 14:21:27

C语言内存管理

C程序的内存布局分为以下几个段&#xff1a; 1. 代码段&#xff08;Text Segment&#xff09;&#xff1a;程序启动时分配&#xff0c;位置固定 2. 数据段&#xff08;Data Segment&#xff1a;程序启动时分配&#xff0c;位置固定a. 初始化数据段&#xff08;Initialized Data…

作者头像 李华
网站建设 2026/8/27 14:21:02

多传感器模块设计指南:从选型到固件的可穿戴实践

我在做可穿戴设备原型验证的时候&#xff0c;最烦的一件事不是算法写不出来&#xff0c;而是传感器接线。IMU焊一块、气压计飞几根线、温湿度再挂一个I2C分支&#xff0c;面包板上密密麻麻全是杜邦线&#xff0c;稍微动一下接触不良&#xff0c;数据直接飘到外太空。后来我干脆…

作者头像 李华