有一个令人费解的要求。
基本上我需要使用这些标准创建唯一ID
以下是我的考虑:
一个。系统时间可能由服务器管理员更改 湾可能会引起问题 如果在相同的毫秒内询问2个请求。
有什么想法吗?
答案 0 :(得分:5)
没有从数据库生成序列号
我讨厌那种愚蠢的要求。我说你作弊并使用像H2或HSQLDB这样的嵌入式数据库,并通过序列生成标识符。
编辑:让我向我展示为什么我提出这个“作弊”:我对“无数据库”要求的理解是要么不安装数据库软件来处理这个要求,要么无法更改现有数据库架构。使用嵌入式数据库与向项目添加新的jar文件是一回事。为什么你不应该这样做?当关系数据库已经为您解决了这个问题时,为什么要自己实现呢?
答案 1 :(得分:2)
处理1,000,000个ID的九位数给我们三个数字(ID为0-999999需要另外六个)。
我假设你有一个多服务器设置。为每个服务器分配一个三位数的服务器ID,然后您可以在每个服务器中分配唯一的ID值,而不必担心它们之间的重叠。它可能只是内存中不断增加的值,除了在JVM重启之后,我们需要将最近分配的值回显到磁盘(好吧,到你想要存储它的任何地方 - 本地磁盘,内存缓存等)。
为了确保不会在每个请求上达到文件/任何I / O的开销,您可以在块中分配ID,将块的端点回送到存储。
所以它最终成为:
在伪代码:
class IDAllocator {
Storage storage;
int nextId;
int idCount;
int blockSize;
long lastIdTime;
/**
* Creates an IDAllocator with the given server ID, backing storage,
* and block size.
*
* @param serverId the ID of the server (e.g., 12)
* @param s the backing storage to use
* @param size the block size to use
* @throws SomeException if something goes wrong
*/
IDAllocator(int serverId, Storage s, int size)
throws SomeException {
// Remember our info
this.serverId = serverId * 1000000; // Add a million to make life easy
this.storage = s;
this.nextId = 0;
this.idCount = 0;
this.blockSize = bs;
this.lastIdTime = this.getDayMilliseconds();
// Get the first block. If you like and depending on
// what container this code is running in, you could
// spin this out to a separate thread.
this.getBlock();
}
public synchronized int getNextId()
throws SomeException {
int id;
// If we're out of IDs, or if the day has changed, get a new block
if (idCount == 0 || this.lastIdTime < this.getDayMilliseconds()) {
this.getBlock();
}
// Alloc from the block
id = this.nextId;
--this.idCount;
++this.nextId;
// If you wanted (and depending on what container this
// code is running in), you could proactively retrieve
// the next block here if you were getting low...
// Return the ID
return id + this.serverId;
}
protected long getDayMilliseconds() {
return System.currentTimeMillis() % 86400000;
}
protected void getBlock()
throws SomeException {
int id;
synchronized (this) {
synchronized (this.storage.syncRoot()) {
id = this.storage.readIntFromStorage();
this.storage.writeIntToStroage(id + blocksize);
}
this.nextId = id;
this.idCount = blocksize;
}
}
}
...但是再次,那是伪代码,你可能想在那里抛出一些主动的东西,这样你就不会在需要时阻止I / O等待ID。
上面的内容是假设您已经拥有某种应用程序范围的单例,并且IDAllocator
实例只是该单个实例中的数据成员。如果没有,你可以通过给它提供经典的getInstance
方法并让它从环境中读取它的配置而不是将它作为构造函数的参数接收来轻松地使上面的单例成为单例。
答案 2 :(得分:1)
服务器1的计数从1到999.999.999怎么样? 对于服务器2,从-999.999.999计算到-1。
我认为由于负载平衡,平衡将大约为50:50。因此,每个服务器都有相同的id范围。此外,您将最后生成的ID存储在文件系统中。由于性能问题,只需存储每1000个值(或10000,这并不重要)。重新启动应用程序后,读取最后生成的值并添加1000.我猜这样可行。
答案 3 :(得分:0)
您可以尝试使用Apache的RandomStringUtils String random(int count, boolean letters, boolean numbers)或尝试使用Java TRNG Client library,然后使用RANDOM.ORG:
该库提供与Java集成的SecureRandom服务 Security API,用于访问random.org和random.irb.hr(真随机 数字生成器通过大气噪声或生成随机性 光子发射)。
我认为如果你得到其中一个并将其与时间戳结合起来,你应该得到你想要的东西。