Java 9位数字的全天唯一ID

Java 9位数字的全天唯一ID,java,uniqueidentifier,Java,Uniqueidentifier,有一个令人费解的要求 基本上,我需要用这些条件创建唯一的id 9位数字,当天唯一(表示如果第二天该数字再次出现就可以了) 实时生成;仅限java(意味着没有从数据库生成序列号-实际上根本没有数据库访问) 生成该编号是为了填充requestID,每天将生成大约1.000.000个id 不应使用UUID或UID(超过9位) 以下是我的考虑: 使用序列号听起来不错,但如果JVM重新启动 可能会重新生成requestId 使用时间HHMMSSS(小时-分钟-秒-毫秒)有2个问题: a。服务器管理

有一个令人费解的要求

基本上,我需要用这些条件创建唯一的id

  • 9位数字,当天唯一(表示如果第二天该数字再次出现就可以了)
  • 实时生成;仅限java(意味着没有从数据库生成序列号-实际上根本没有数据库访问)
  • 生成该编号是为了填充requestID,每天将生成大约1.000.000个id
  • 不应使用UUID或UID(超过9位)
以下是我的考虑:

  • 使用序列号听起来不错,但如果JVM重新启动 可能会重新生成requestId
  • 使用时间HHMMSSS(小时-分钟-秒-毫秒)有2个问题:
a。服务器管理员可能会更改系统小时数。
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
实例将只是该单例中的一个数据成员。如果不是,您可以很容易地将上述内容改为单例