Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 好的生成方法;系统“;唯一ID_Java_Mysql_Hibernate_Jpa_Identifier - Fatal编程技术网

Java 好的生成方法;系统“;唯一ID

Java 好的生成方法;系统“;唯一ID,java,mysql,hibernate,jpa,identifier,Java,Mysql,Hibernate,Jpa,Identifier,我目前使用Hibernate作为JPA提供程序,我想将IDs生成从持久层切换到应用层 我的模式(在MySQL 5.7上)目前正在使用BIGINT(20)数据类型作为ID,但我不想为了UUID而进行重构 所以我认为像“系统”UID这样的东西就足够了: public static long getUID() { long key = getSystemKey() << 56; // like 0x0100000000000000L; long ts = System.cu

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

我的模式(在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;
}
其中
getSystemKey()
[
K
]为运行应用程序的每台“机器”返回唯一的固定字节(在配置文件中声明)

时间戳
ts
[
T
]使用了11个字节,确保有足够的毫秒来
2527-06-23 08:20:44.415

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

所以我想知道这种方法是否足够一致,利弊如何,是否有更好的方法

谢谢


更新 我用100个线程和10000次执行测试了此方法:

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);
}
publicstaticvoidmain(字符串[]args)引发异常
{
List runner=new ArrayList();
对于(int i=0;i<10000;i++)
{
添加(SUID::random);
}
ExecutorService池=Executors.newFixedThreadPool(100);
列表结果=pool.invokeAll(运行者);
pool.shutdown();
int-dups=0;
Set id=new HashSet();
用于(未来:结果)
{
如果(!ids.add(future.get()))
{
dups++;
}
}
系统输出打印项次(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();
    }
}
公共最终类SUID
{

private static final AtomicLong SEQUENCE=new AtomicLong(Config.getSystemKey())如果您手动设置Id列的值,它将不会使用任何生成器。当您显然表示nybles(半字节)时,您已经多次使用了“bytes”(字节)。
KK ttttttttttttt RRR
如您所述,它实际上是16 nybles(4位×16=64位),而不是16个字节(8位×16=128位)。您描述的算法有点像MySQL内置函数,它也返回一个64位无符号整数,并且类似地用一个值初始化,包括
(@@SERVER\u ID&0xFF)您是对的,我开始是以字节为单位,但以nybles(奇数ts)结束我不知道。这似乎也是一个很好的折衷方案,但我想避免同步。你看到什么缺点了吗?
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();
    }
}