Java中的顺序GUID

12

考虑到我之前在Microsoft.NET框架上关于顺序GUID性能的帖子(请参见“顺序GUID相对标准GUID有什么性能优势?”),是否有人拥有该算法的适当、可靠、快速且有效的Java实现,就像Windows DLLs中实现的一样?

问候 马西莫

5个回答

6
请参阅此文章:http://www.informit.com/articles/article.aspx?p=25862&seqNum=7(链接到第7页)。
该文章包含一种作者称之为“COMB” Guids的算法;我在下面重现了他的代码(SQL)。
SET @aGuid = CAST(CAST(NEWID() AS BINARY(10)) 
+ CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER)

将此转换为Java或您所需的语言非常简单。显而易见的基本原则是使日期成为Guid的组成部分。整篇文章都值得一读,因为他对各种方法的性能进行了很好的分析。


3
对于连续的 UUID,您需要查找版本 1 的 UUID。Java UUID 生成器项目似乎工作得非常好,并且非常易于使用:Java UUID Generator
Generators.timeBasedGenerator().generate().toString()

2
链接似乎已经失效。一些搜索结果显示这可能是在此处讨论的项目:https://github.com/cowtowncoder/java-uuid-generator - vazor
谢谢。初步看起来生成的 UUID 是顺序的。也许我的防止页面分裂的战斗还没有失败。 - frankieta

2

0
这是一个实用类,用于生成COMB UUIDs,由Jimmy Nilsson在这篇文章中提出:http://www.informit.com/articles/article.aspx?p=25862。欢迎使用和分享。
package your.package.name;

import java.security.SecureRandom;
import java.util.Random;
import java.util.UUID;

/**
 * Utility class that creates COMB UUIDs.
 * 
 * The COMB UUIDs combine the creation time and random bytes.
 * 
 * The PREFIX or SUFFIX has 6 bytes and corresponds to the milliseconds since
 * 1970-01-01T00:00:00Z (Unix epoch).
 * 
 * For RFC-4122 compliance, it uses the version number 4.
 * 
 * Read: The Cost of GUIDs as Primary Keys
 * http://www.informit.com/articles/article.aspx?p=25862
 * 
 */
public abstract class CombUuidCreator {

    private static final int RANDOM_VERSION = 4;

    /**
     * Returns a prefix COMB UUID.
     * 
     * It uses a thread local {@link SecureRandom}.
     * 
     * @return a random-based UUID
     */
    public static UUID getPrefixComb() {
        return getPrefixComb(SecureRandomLazyHolder.THREAD_LOCAL_RANDOM.get());
    }

    /**
     * Returns a prefix COMB UUID.
     * 
     * It uses any instance of {@link Random}.
     * 
     * @return a random-based UUID
     */
    public static UUID getPrefixComb(Random random) {
        return getCombGuid(random, /* prefix = */true);
    }

    /**
     * Returns a suffix COMB UUID.
     * 
     * It uses a thread local {@link SecureRandom}.
     * 
     * @return a random-based UUID
     */
    public static UUID getSuffixComb() {
        return getSuffixComb(SecureRandomLazyHolder.THREAD_LOCAL_RANDOM.get());
    }

    /**
     * Returns a suffix COMB UUID.
     * 
     * It uses any instance of {@link Random}.
     * 
     * @return a random-based UUID
     */
    public static UUID getSuffixComb(Random random) {
        return getCombGuid(random, /* prefix = */false);
    }

    /**
     * Returns prefix or suffix COMB UUID.
     * 
     * It uses any instance of {@link Random}.
     * 
     * @return a random-based UUID
     */
    private static UUID getCombGuid(Random random, boolean prefix) {

        long msb = 0;
        long lsb = 0;

        // (3) set bits randomly
        final byte[] bytes = new byte[16];
        random.nextBytes(bytes);
        final long rand0 = (bytes[8] << 8) | (bytes[9] & 0xff);
        final long rand1 = toNumber(bytes, 0, 8);

        // Insert the prefix in the MSB
        final long timestamp = System.currentTimeMillis();
        if (prefix) {
            msb = (rand0 & 0x000000000000ffffL) | ((timestamp & 0x0000ffffffffffffL) << 16);
            lsb = rand1;
        } else {
            msb = rand1;
            lsb = (rand0 << 48) | (timestamp & 0x0000ffffffffffffL);
        }

        // Apply version and variant bits (required for RFC-4122 compliance)
        msb = (msb & 0xffffffffffff0fffL) | (RANDOM_VERSION & 0x0f) << 12; // apply version bits
        lsb = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // apply variant bits

        // Return the UUID
        return new UUID(msb, lsb);
    }

    private static long toNumber(final byte[] bytes, final int start, final int length) {
        long result = 0;
        for (int i = start; i < length; i++) {
            result = (result << 8) | (bytes[i] & 0xff);
        }
        return result;
    }

    // Holds thread local secure random
    private static class SecureRandomLazyHolder {
        static final ThreadLocal<Random> THREAD_LOCAL_RANDOM = ThreadLocal.withInitial(SecureRandom::new);
    }

    /**
     * For tests!
     */
    public static void main(String[] args) {

        Random random = new Random();

        System.out.println("// Prefix COMB using thread local `java.security.SecureRandom` (DEFAULT)");
        System.out.println("CombUuidCreator.getPrefixComb()");
        System.out.println();
        for (int i = 0; i < 5; i++) {
            System.out.println(" " + CombUuidCreator.getPrefixComb());
        }
        System.out.println("|----prefix---|----------------------|");

        System.out.println();
        System.out.println("// Prefix COMB using `java.util.Random` (FASTER)");
        System.out.println("CombUuidCreator.getPrefixComb(new Random())");
        System.out.println();
        for (int i = 0; i < 5; i++) {
            System.out.println(" " + CombUuidCreator.getPrefixComb(random));
        }
        System.out.println("|----prefix---|----------------------|");

        System.out.println();
        System.out.println("// Suffix COMB using thread local `java.security.SecureRandom` (DEFAULT)");
        System.out.println("CombUuidCreator.getSuffixComb()");
        System.out.println();
        for (int i = 0; i < 5; i++) {
            System.out.println(" " + CombUuidCreator.getSuffixComb());
        }
        System.out.println("|-----------------------|---suffix---|");

        System.out.println();
        System.out.println("// Suffix COMB using `java.util.Random` (FASTER)");
        System.out.println("CombUuidCreator.getSuffixComb(new Random())");
        System.out.println();
        for (int i = 0; i < 5; i++) {
            System.out.println(" " + CombUuidCreator.getSuffixComb(random));
        }
        System.out.println("|-----------------------|---suffix---|");
    }
}

这是输出结果:

// Prefix COMB using thread local `java.security.SecureRandom` (DEFAULT)
CombUuidCreator.getPrefixComb()

 0173861f-4445-459b-87d2-39a970520fff
 0173861f-4445-465d-a216-7b13d86c83a1
 0173861f-4445-4c67-b75e-3845c2911420
|----prefix---|----------------------|

// Prefix COMB using `java.util.Random` (FASTER)
CombUuidCreator.getPrefixComb(new Random())

 0173861f-4445-44f6-bfa4-e272c9c369aa
 0173861f-4445-446e-baf2-6db6ab808094
 0173861f-4445-40e8-a452-184dcf9736fd
|----prefix---|----------------------|

// Suffix COMB using thread local `java.security.SecureRandom` (DEFAULT)
CombUuidCreator.getSuffixComb()

 726b6717-001a-4317-9a9b-0173861f4446
 dfdce2d2-7517-4a3f-9f3d-0173861f4446
 a7fd6236-8065-4395-b49a-0173861f4446
|-----------------------|---suffix---|

// Suffix COMB using `java.util.Random` (FASTER)
CombUuidCreator.getSuffixComb(new Random())

 41a6a4cd-eb4c-410f-8eb2-0173861f4446
 7c0a315e-54de-476a-a2a8-0173861f4446
 4e9ddf9e-ac07-4cf3-bf3f-0173861f4446
|-----------------------|---suffix---|

您还可以使用uuid-creator库。请参考以下示例:

// Create a prefix COMB UUID
UUID uuid = UuidCreator.getPrefixComb();

// Create a suffix COMB UUID
UUID uuid = UuidCreator.getSuffixComb();

项目页面:https://github.com/f4b6a3/uuid-creator


-3
我使用这个来生成UUID(通用唯一标识符)作为我的DTO的替代键,用于临时集合。不知道是否是同样的东西,但可能会指引你朝正确的方向发展。
import java.util.UUID;
...
    private String uuid=null;
...
    protected String getUuid() {
        synchronized (this) {
          if (null ==uuid) {
            uuid = UUID.randomUUID().toString();
          }
          return uuid;
        }
      }

1
不,这会创建一个标准的随机 GUID,我需要一个连续的 GUID。 - massimogentilini

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接