生成"系统"的好方法独特的ID

时间:2017-03-25 11:34:51

标签: java mysql hibernate jpa identifier

我目前正在使用Hibernate作为JPA提供程序,我想将ID生成从持久层切换到应用程序层。

我的架构(在MySQL 5.7上)目前正在使用BIGINT(20)数据类型来识别ID,但我不想重构以获取UUID。

所以我认为像是"系统" UID应该足够了:

public static long getUID()
{
    long key = getSystemKey() << 56; // like 0x0100000000000000L;
    long ts = System.currentTimeMillis() << 12;
    int r = new Random().nextInt(0xFFF);
    long id = key + ts + r;

    return id;
}

生成的ID的格式为

KK TTTTTTTTTTT RRR

其中getSystemKey() [K]返回每个&#34;机器的唯一固定字节&#34;应用程序正在运行(它在配置文件中声明)。

时间戳ts [T]正在使用11个nybbles,确保有足够的毫秒到2527-06-23 08:20:44.415

random r [R]用于添加每台机器每毫秒的随机性(最后3个nybbles)。

所以我想知道这种方式是否足够一致,有什么利弊,以及是否有更好的方式。

由于

更新

我用100个线程和10,000个执行测试了这个方法:

public static void main(String[] args) throws Exception
{
    List<Callable<Long>> runners = new ArrayList<>();
    for(int i = 0; i < 10000; i++)
    {
        runners.add(SUID::random);
    }

    ExecutorService pool = Executors.newFixedThreadPool(100);
    List<Future<Long>> results = pool.invokeAll(runners);
    pool.shutdown();

    int dups = 0;
    Set<Long> ids = new HashSet<>();
    for(Future<Long> future : results)
    {
        if(!ids.add(future.get()))
        {
            dups++;
        }
    }

    System.out.println(dups);
}

我有大约6%的碰撞。

所以,唯一的方法似乎是使用一些同步:

public final class SUID
{
    private static final AtomicLong SEQUENCE = new AtomicLong(Config.getSystemKey() << 56 | System.currentTimeMillis() << 12);

    private SUID()
    {
        super();
    }

    public static long generate()
    {
        return SEQUENCE.incrementAndGet();
    }
}

0 个答案:

没有答案