Java 9位数字的全天唯一ID
有一个令人费解的要求 基本上,我需要用这些条件创建唯一的idJava 9位数字的全天唯一ID,java,uniqueidentifier,Java,Uniqueidentifier,有一个令人费解的要求 基本上,我需要用这些条件创建唯一的id 9位数字,当天唯一(表示如果第二天该数字再次出现就可以了) 实时生成;仅限java(意味着没有从数据库生成序列号-实际上根本没有数据库访问) 生成该编号是为了填充requestID,每天将生成大约1.000.000个id 不应使用UUID或UID(超过9位) 以下是我的考虑: 使用序列号听起来不错,但如果JVM重新启动 可能会重新生成requestId 使用时间HHMMSSS(小时-分钟-秒-毫秒)有2个问题: a。服务器管理
- 9位数字,当天唯一(表示如果第二天该数字再次出现就可以了)
- 实时生成;仅限java(意味着没有从数据库生成序列号-实际上根本没有数据库访问)
- 生成该编号是为了填充requestID,每天将生成大约1.000.000个id
- 不应使用UUID或UID(超过9位)
- 使用序列号听起来不错,但如果JVM重新启动 可能会重新生成requestId
- 使用时间HHMMSSS(小时-分钟-秒-毫秒)有2个问题:
B可能引起问题 如果在同一毫秒内询问两个请求 有什么想法吗 没有从数据库生成序列号 我讨厌那种愚蠢的要求。我说,你作弊,使用一个嵌入式数据库,比如or,然后通过一个序列生成标识符
编辑:让我详细解释一下我为什么提出这个“欺骗”:我对“无数据库”要求的理解是,要么不应该安装数据库软件来处理这个要求,要么现有的数据库模式不能更改。使用嵌入式数据库与向项目中添加新的jar文件是一样的。为什么你不应该这样做?既然关系数据库已经为您解决了这个问题,为什么还要自己实现呢?您可以试用Apache或尝试使用RANDOM.ORG: 该库提供了一个与Java集成的SecureRandom服务 安全API,用于访问random.org和random.irb.hr(真随机 对通过大气噪声或噪声产生随机性的生成器进行编号 光子发射)
我认为,如果你得到其中一个,并将其与时间戳相结合,你应该得到你想要的。处理1000000个ID的九位数字给了我们三位数字(我们需要其他六位数字来处理ID的0-999999) 我假设您有一个多服务器设置。为每台服务器分配一个三位数的服务器ID,然后您可以在每台服务器内分配唯一的ID值,而不必担心它们之间的重叠。它在内存中可能是一个不断增加的值,除了要在JVM重新启动后生存,我们需要将最近分配的值回显到磁盘上(好的,回显到您想要存储它的任何地方—本地磁盘、memcache,等等) 为了确保不会影响每个请求的文件/任何I/O开销,可以在块中分配ID,将块的端点回显到存储器 因此,它最终是:
- 给每个服务器一个ID
- 在服务器上存储当天最后分配的值(例如文件)
- 让ID分配器分块工作(每次10个ID,100个,随便什么)
- 要分配块,请执行以下操作:
- 读取文件,写回按块大小增加的数字
- 使用块中的ID
- 服务器12分配的第28个ID为12000000027
- 当一天发生变化时(例如,午夜),扔掉当前区块,为新的一天分配一个新区块
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;
}
}
}
类IDAllocator{
储存;
int nextId;
int-idCount;
整块大小;
长时间;
/**
*使用给定的服务器ID创建IDAllocator,备份存储,
*和块大小。
*
*@param serverId服务器的ID(例如12)
*@param s要使用的备份存储
*@param size要使用的块大小
*@在出现问题时抛出异常
*/
IDAllocator(int服务器ID、存储器s、int大小)
抛出一些异常{
//记住我们的信息
this.serverId=serverId*1000000;//增加一百万使生活更轻松
这个存储=s;
this.nextId=0;
此值为0.idCount=0;
这个.blockSize=bs;
this.lastIdTime=this.getdaymissions();
//去第一个街区。如果你喜欢的话
//您可以在哪个容器中运行此代码
//把它旋成一条单独的线。
这个.getBlock();
}
public synchronized int getNextId()
抛出一些异常{
int-id;
//如果我们的ID用完了,或者日子变了,就换一个新的区块
如果(idCount==0 | | this.lastIdTime
…但同样,这是伪代码,您可能希望在其中加入一些主动式的东西,以便在需要ID时不会阻止I/O等待ID
上面的内容是假设您已经有某种应用程序范围的单例,并且IDAllocator
实例将只是该单例中的一个数据成员。如果不是,您可以很容易地将上述内容改为单例