的PostgreSQL:
create extension if not exists "uuid-ossp";
select uuid_generate_v3(uuid_nil(), 'this is a test');
uuid_generate_v3
--------------------------------------
e1e27115-9f5b-366d-90e8-e07b1b36b99c
(1 row)
爪哇:
java> java.util.UUID.nameUUIDFromBytes("this is a test".getBytes());
java.util.UUID res9 = 54b0c58c-7ce9-32a8-b551-351102ee0938
如何在Java中生成与PostgreSQL相同的UUID?
答案 0 :(得分:1)
据我所知,没有直接的方式,你必须深入研究PostgreSQL(及其库)的源代码,并自己用Java复制算法,或者调用本地相同的库函数。一个更简单的选择是让PostgreSQL数据库为您生成它们,但我认为由于某种原因这是不可能的。
从the documentation可以看出,PostgreSQL首先采用MD5哈希来防止逆向工程。然后,他们使用OSSP UUID库中的UUID生成器。
我试过了:
1> select newid(),newid(1)
2> go
------------------------------------ ------------------------------------
086ae8a4920944dcb45f81b8c983b3f1 3c23dabf-d989-48dc-807b-81b8c983b3f1
但那产生了:
java.util.UUID.nameUUIDFromBytes(Md5Utils.getMd5Digest("this is a test"));
答案 1 :(得分:1)
此处https://tools.ietf.org/html/rfc4122#section-4.3
描述了用于生成版本3 UUID的算法但是关键步骤是:
postgres函数签名为uuid_generate_v3(namespace uuid, name text)
,因此它将名称空间UUID和name
作为参数。
Java方法nameUUIDFromBytes(byte[] name)
仅采用name
并用MD5对其进行哈希处理以创建UUID。为了获得与PostgreSQL相同的输出,您必须自己将名称空间字节和name
字节连接在一起。
对于命名空间,您使用了uuid_nil()
(在Java中为new UUID(0L, 0L)
)。
将所有内容放在一起看起来像这样:
byte[] bytes = Arrays.concatenate(toByteArray(new UUID(0L, 0L)), "this is a test".getBytes(StandardCharsets.UTF_8));
System.out.println(UUID.nameUUIDFromBytes(bytes)); // prints out e1e27115-9f5b-366d-90e8-e07b1b36b99c
您可以将名称空间UUID转换为字节数组,如下所示:
private static byte[] toByteArray(UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
}
答案 2 :(得分:0)
尽管这不是原始问题的答案,但是我不得不以另一种方式进行此转换,即在迁移过程中模仿PostgreSQL中的UUID.nameUUIDFromBytes
行为:
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE EXTENSION IF NOT EXISTS "plpgsql";
CREATE OR REPLACE FUNCTION uuidv3(bytes bytea)
RETURNS uuid
RETURNS null on null input
STABLE
PARALLEL SAFE
AS $$
DECLARE
md5bytes bytea;
BEGIN
md5bytes := digest(bytes, 'md5');
-- md5Bytes[6] &= 0x0f; /* clear version */
-- md5Bytes[6] |= 0x30; /* set to version 3 */
md5bytes := set_byte(md5bytes, 6, (get_byte(md5bytes, 6) & x'0F'::int) | x'30'::int);
-- md5Bytes[8] &= 0x3f; /* clear variant */
-- md5Bytes[8] |= 0x80; /* set to IETF variant */
md5bytes := set_byte(md5bytes, 8, (get_byte(md5bytes, 8) & x'3F'::int)| x'80'::int);
RETURN (encode(md5bytes, 'hex'))::uuid;
END
$$
LANGUAGE plpgsql;
,您应该使用内部textsend
将文本列转换为bytea
:
SELECT uuidv3(textsend('this is a test'));
尽管我必须承认我从未尝试过其他方法。