Java 好的生成方法;系统“;唯一ID
我目前使用Hibernate作为JPA提供程序,我想将IDs生成从持久层切换到应用层 我的模式(在MySQL 5.7上)目前正在使用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
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();
}
}