固定长度的唯一ID创建

发布于 2024-12-15 01:45:11 字数 856 浏览 2 评论 0原文

嗯,我一直在寻找在 java 代码中生成 UID 的方法(其中大多数也出现在 stackoverflow 上)。最好是使用 java 的 UUID 来创建唯一的 id,因为它使用时间戳。但我的问题是它是 128 位长,我需要一个更短的字符串,比如 14 或 15 个字符。因此,我设计了以下代码来执行此操作。

Date date = new Date();
Long luid = (Long) date.getTime();
String suid = luid.toString();
System.out.println(suid+": "+suid.length() + " characters");

Random rn = new Random();
Integer long1 = rn.nextInt(9);
Integer long2 = rn.nextInt(13);

String newstr = suid.substring(0, long2) + " " + long1 + " " + suid.subtring(long2);
System.out.println("New string in spaced format: "+newstr);
System.out.println("New string in proper format: "+newstr.replaceAll(" ", ""));

请注意,我只是显示间隔格式和格式正确的字符串,仅用于与原始字符串进行比较。

这能保证每次都有 100% 唯一的 id 吗?或者你认为这些数字有可能重复吗?另外,我可以在开头或结尾执行此操作,而不是将随机数插入“可能”创建重复数字的随机位置。这是为了完成我的 UID 所需的长度。尽管如果您需要少于 13 个字符的 UID,这可能不起作用。

有什么想法吗?

Well, I have been looking at ways to generate UIDs in java code (most of them coming to stackoverflow too). The best is to use java's UUID to create unique ids since it uses the timestamp. But my problem is that it is 128-bit long and I need a shorter string, like say 14 or 15 characters. So, I devised the following code to do so.

Date date = new Date();
Long luid = (Long) date.getTime();
String suid = luid.toString();
System.out.println(suid+": "+suid.length() + " characters");

Random rn = new Random();
Integer long1 = rn.nextInt(9);
Integer long2 = rn.nextInt(13);

String newstr = suid.substring(0, long2) + " " + long1 + " " + suid.subtring(long2);
System.out.println("New string in spaced format: "+newstr);
System.out.println("New string in proper format: "+newstr.replaceAll(" ", ""));

Please note that I am just displaying the spaced-formatted and properly-formatted string for comparison with the original string only.

Would this guarantee a 100% unique id each time? Or do you see any possibility the numbers could be repeated? Also, instead of inserting a random number into a random position which "might" create duplicate numbers, I could do it either in the beginning or end. This is to complete the required length of my UID. Although this might probably not work if you need a UID less than 13 characters.

Any thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

随波逐流 2024-12-22 01:45:11

当然,如果这是一个分布式系统,那么这是行不通的,但是像下面这样的系统怎么样?

private AtomicLong uniqueId = new AtomicLong(0);
...
// get a unique current-time-millis value 
long now;
long prev;
do {
    prev = uniqueId.get();
    now = System.currentTimeMillis();
    // make sure now is moving ahead and unique
    if (now <= prev) {
        now = prev + 1;
    }
    // loop if someone else has updated the id
} while (!uniqueId.compareAndSet(prev, now));

// shuffle it
long result = shuffleBits(now);
System.out.println("Result is " + Long.toHexString(result));

public static long shuffleBits(long val) {
    long result = 0;
    result |= (val & 0xFF00000000000000L) >> 56;
    result |= (val & 0x00FF000000000000L) >> 40;
    result |= (val & 0x0000FF0000000000L) >> 24;
    result |= (val & 0x000000FF00000000L) >> 8;
    result |= (val & 0x00000000FF000000L) << 8;
    result |= (val & 0x0000000000FF0000L) << 24;
    result |= (val & 0x000000000000FF00L) << 40;
    result |= (val & 0x00000000000000FFL) << 56;
    return result;
}

可以改进位改组,以在每次迭代的值中产生更多变化。您提到您不希望数字是连续的,但您没有指定完全随机性的要求。

当然不如UUID,但比数据库操作更快。

This won't work if this is a distributed system of course but how about something like the following.

private AtomicLong uniqueId = new AtomicLong(0);
...
// get a unique current-time-millis value 
long now;
long prev;
do {
    prev = uniqueId.get();
    now = System.currentTimeMillis();
    // make sure now is moving ahead and unique
    if (now <= prev) {
        now = prev + 1;
    }
    // loop if someone else has updated the id
} while (!uniqueId.compareAndSet(prev, now));

// shuffle it
long result = shuffleBits(now);
System.out.println("Result is " + Long.toHexString(result));

public static long shuffleBits(long val) {
    long result = 0;
    result |= (val & 0xFF00000000000000L) >> 56;
    result |= (val & 0x00FF000000000000L) >> 40;
    result |= (val & 0x0000FF0000000000L) >> 24;
    result |= (val & 0x000000FF00000000L) >> 8;
    result |= (val & 0x00000000FF000000L) << 8;
    result |= (val & 0x0000000000FF0000L) << 24;
    result |= (val & 0x000000000000FF00L) << 40;
    result |= (val & 0x00000000000000FFL) << 56;
    return result;
}

The bit shuffling could be improved on to generate more change in the values each iteration. You mentioned that you don't want the numbers to be sequential but you didn't specify a requirement for full random-ness.

Certainly not as good as the UUID but faster then the database operation.

南风起 2024-12-22 01:45:11

最简单的方法是使用数据库序列(如果可用)。如果不是,您可以按如下方式模拟它们:

  1. 创建一个表,其中有一列将保存最大值
    到目前为止已使用(最初为 0)。某些应用程序会创建多行
    其中每一行控制一个特定的唯一 ID,但您真正
    需要的是一排。对于此示例,假设表结构如下
    如下:

    <前><代码>ID_TABLE
    ID_NAME VARCHAR(40); -- 或者任何合适的类型
    ID_COLUMN 整数; -- 或者任何合适的类型

  2. 每个进程通过执行以下操作来保留行:

    <前><代码>a。开始发送;
    b.更新 ID_TABLE 设置 ID_VALUE = ID_VALUE +;其中 ID_NAME = <名称>;
    c.从 ID_TABLE 中选择 ID_VALUE,其中 ID_NAME = <名称>;
    d.提交交易;

    如果这一切都成功完成,那么您刚刚保留了
    范围 (val - n + 1) 到 val,其中 val 是步骤 c 的返回值。 每个进程通过执行以下

  3. 每个进程都会从其保留的范围内分发 ID。如果
    进程是多线程的,它必须提供同步以确保
    每个值最多分发一次。当它的供应耗尽时
    返回到步骤 2 并保留更多值。笔记
    并非所有保留的值都保证被使用。如果
    进程在未使用其拥有的所有值的情况下终止
    保留,未使用的值将丢失并且永远不会使用。

The easy way is use database sequences if they are available. If they aren't, you can simulate them as follows:

  1. Create a table that has a column that will hold the maximum value
    used so far (initially 0). Some applications create multiple rows
    where each row controls a specific unique ID, but all you really
    need is one row. For this example assume the table structure is as
    follows:

    ID_TABLE
    ID_NAME    VARCHAR(40); -- Or whatever type is appropriate
    ID_COLUMN  INTEGER; -- Or whatever type is appropriate
    
  2. Each process reserves rows, by doing the following:

    a. Begin Txn;
    b. Update ID_TABLE set ID_VALUE = ID_VALUE + <n> where ID_NAME = <name>;     
    c. Select ID_VALUE from ID_TABLE where ID_NAME = <name>;  
    d. Commit Txn;
    

    If this all completes successfully, then you have just reserved the
    range (val - n + 1) through val where val is the returned value from step c. above.

  3. Each process hands out IDs from the range it reserved. If the
    process is multi-threaded it must provide synchronization to ensure
    each value is handed out at most once. When it exhausts its supply
    of values it goes back to step 2 and reserves more values. Note
    that not all values that are reserved are guaranteed to be used. If
    a process terminates without using all of the values it has
    reserved, the unused values are lost and never used.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文