在Java Sping Boot 项目中使用System.currentTimeMillis()作为唯一标识符是否会导致竞争条件,即有人可以在同一毫秒内命中API?这是什么机会。有没有办法生成一个特定长度的唯一标识符(16-18字符),因为GUID的长度是36个字符。
System.currentTimeMillis()
brvekthn1#
我不会称之为竞争条件,但在同一毫秒内收到两个请求是可能的。这几率有多大?这取决于如何使用它。如果我想每毫秒发出很多请求,我可以。如果我很小心地不去做,那也是可能的。您可能想使用UUID.randomUUID()。大多数数据库都支持这些,甚至可以为您生成它们。它们不会明显更贵。当然,您可以使用类似大小的随机数,并以不同的格式对其进行编码。GUID使用十六进制,与base64之类的东西相比,它需要很多字符。
UUID.randomUUID()
gpnt7bae2#
据猜测,一旦有1000个并发用户,机会就得到了保证。为什么是16个字符?似乎是武断的。你可以使用一个随机数生成器,并保持一个超时Map,并保持跟踪用户的方式,我猜?但是为什么不使用Spring支持的cookie会话ID呢?
vq8itlhq3#
System.currentTimeMillis()的Javadoc说:以毫秒为单位返回当前时间。请注意,虽然返回值的时间单位是毫秒,但值的粒度取决于底层操作系统,可能会更大。例如,许多操作系统以几十毫秒为单位来测量时间。即使您具有毫秒级的粒度,冲突也会以一定的频率发生。例如,假设有10个用户在同一秒内访问API。特定请求发生冲突的概率为10 / 1000 = 1%。如果碰撞导致用户可见的故障,则可能高得无法容忍。如果你想要像UUID.randomUUID这样的东西,只是更短,为什么不从中汲取灵感呢?下面是它的实现:
UUID.randomUUID
public static UUID randomUUID() { SecureRandom ng = Holder.numberGenerator; byte[] randomBytes = new byte[16]; ng.nextBytes(randomBytes); randomBytes[6] &= 0x0f; /* clear version */ randomBytes[6] |= 0x40; /* set to version 4 */ randomBytes[8] &= 0x3f; /* clear variant */ randomBytes[8] |= (byte) 0x80; /* set to IETF variant */ return new UUID(randomBytes); }
所以基本上,它只是在某个地方有一个SecureRandom,向它请求16个随机字节,将这些字节转换为UUID标准的形式。您不需要UUID标准,并且需要少于16个字节。为什么不这样做呢?
SecureRandom
class MyRandomIdGenerator { static SecureRandom generator = new SecureRandom(); static long nextId() { return generator.nextLong(); } }
最长的long是十进制中的19个字符。您可以使用十六进制表示法将其减少到16,或者以8字节的二进制格式存储它。如果负ID困扰您,您可以始终使用
long
return generator.nextLong() >>> 1;
3条答案
按热度按时间brvekthn1#
我不会称之为竞争条件,但在同一毫秒内收到两个请求是可能的。这几率有多大?这取决于如何使用它。如果我想每毫秒发出很多请求,我可以。如果我很小心地不去做,那也是可能的。
您可能想使用
UUID.randomUUID()
。大多数数据库都支持这些,甚至可以为您生成它们。它们不会明显更贵。当然,您可以使用类似大小的随机数,并以不同的格式对其进行编码。GUID使用十六进制,与base64之类的东西相比,它需要很多字符。
gpnt7bae2#
据猜测,一旦有1000个并发用户,机会就得到了保证。
为什么是16个字符?似乎是武断的。你可以使用一个随机数生成器,并保持一个超时Map,并保持跟踪用户的方式,我猜?
但是为什么不使用Spring支持的cookie会话ID呢?
vq8itlhq3#
System.currentTimeMillis()
的Javadoc说:以毫秒为单位返回当前时间。请注意,虽然返回值的时间单位是毫秒,但值的粒度取决于底层操作系统,可能会更大。例如,许多操作系统以几十毫秒为单位来测量时间。
即使您具有毫秒级的粒度,冲突也会以一定的频率发生。例如,假设有10个用户在同一秒内访问API。特定请求发生冲突的概率为10 / 1000 = 1%。如果碰撞导致用户可见的故障,则可能高得无法容忍。
如果你想要像
UUID.randomUUID
这样的东西,只是更短,为什么不从中汲取灵感呢?下面是它的实现:所以基本上,它只是在某个地方有一个
SecureRandom
,向它请求16个随机字节,将这些字节转换为UUID标准的形式。您不需要UUID标准,并且需要少于16个字节。为什么不这样做呢?最长的
long
是十进制中的19个字符。您可以使用十六进制表示法将其减少到16,或者以8字节的二进制格式存储它。如果负ID困扰您,您可以始终使用