为什么需要短ID
数据库操作过程最常用到:
- 自增ID
- UUID
前者多数依赖Mysql的auto_increment,但数据移植麻烦. 如果是主从或主主,不同库里自增ID还可能不一致.
后者长度是个问题.
怎样生成短ID
- 生成UUID
- 哈希murmur为64bit
- 使用64进制显示
public class ClientShardInfo {
public static void main(String[] args) {
Map<Long, Integer> result = new HashMap<>();
long start = System.currentTimeMillis();
for (int i = 0; i < 10000 * 100; i++) {
long hash = nextShortId();
System.out.println(Long.toUnsignedString(hash, 32));
Integer val = result.get(hash);
if (val == null) {
val = 1;
} else {
val++;
}
result.put(hash, val);
}
long end = System.currentTimeMillis();
System.out.println("used time:" + (end - start));
System.out.println(result);
}
public static long nextShortId() {
UUID uuid = UUID.randomUUID();
long h = uuid.getMostSignificantBits();
long l = uuid.getLeastSignificantBits();
byte[] bytes = new byte[16];
bytes[0] = (byte) ((h >>> 56) & 0xFF);
bytes[1] = (byte) ((h >>> 48) & 0xFF);
bytes[2] = (byte) ((h >>> 40) & 0xFF);
bytes[3] = (byte) ((h >>> 32) & 0xFF);
bytes[4] = (byte) ((h >>> 24) & 0xFF);
bytes[5] = (byte) ((h >>> 16) & 0xFF);
bytes[6] = (byte) ((h >>> 8) & 0xFF);
bytes[7] = (byte) (h & 0xFF);
bytes[8] = (byte) ((l >>> 56) & 0xFF);
bytes[9] = (byte) ((l >>> 48) & 0xFF);
bytes[10] = (byte) ((l >>> 40) & 0xFF);
bytes[11] = (byte) ((l >>> 32) & 0xFF);
bytes[12] = (byte) ((l >>> 24) & 0xFF);
bytes[13] = (byte) ((l >>> 16) & 0xFF);
bytes[14] = (byte) ((l >>> 8) & 0xFF);
bytes[15] = (byte) (l & 0xFF);
return Hashing.MURMUR_HASH.hash(bytes);
}
}
生成结果:
- 32进制,5bit一个字符, 64bit大约12~13个字符.
- 用64进制, 6bit一个字符, 64bit大约11~12个字符
循环1000W,碰撞率为0.