9位全天唯一身份证

时间:2012-07-24 08:01:26

标签: java uniqueidentifier

有一个令人费解的要求。

基本上我需要使用这些标准创建唯一ID

  • 9位数字,当天唯一(如果第二天再次显示该数字,则表示没问题)
  • 实时生成;仅限java(表示没有从数据库生成序列号 - 实际上根本没有数据库访问)
  • 生成的数字用于填充requestID,每天将生成大约1.000.000个ID。
  • 不应使用UUID或UID(超过9位)

以下是我的考虑:

  • 使用序列号听起来不错,但是如果JVM重启,那么 requestId可能会被重新生成。
  • 使用时间HHmmssSSS(小时分钟秒毫秒)有2个问题:
  

一个。系统时间可能由服务器管理员更改   湾可能会引起问题   如果在相同的毫秒内询问2个请求。

有什么想法吗?

4 个答案:

答案 0 :(得分:5)

  

没有从数据库生成序列号

我讨厌那种愚蠢的要求。我说你作弊并使用像H2HSQLDB这样的嵌入式数据库,并通过序列生成标识符。

编辑:让我向我展示为什么我提出这个“作弊”:我对“无数据库”要求的理解是要么不安装数据库软件来处理这个要求,要么无法更改现有数据库架构。使用嵌入式数据库与向项目添加新的jar文件是一回事。为什么你不应该这样做?当关系数据库已经为您解决了这个问题时,为什么要自己实现呢?

答案 1 :(得分:2)

处理1,000,000个ID的九位数给我们三个数字(ID为0-999999需要另外六个)。

我假设你有一个多服务器设置。为每个服务器分配一个三位数的服务器ID,然后您可以在每个服务器中分配唯一的ID值,而不必担心它们之间的重叠。它可能只是内存中不断增加的值,除了在JVM重启之后,我们需要将最近分配的值回显到磁盘(好吧,到你想要存储它的任何地方 - 本地磁盘,内存缓存等)。

为了确保不会在每个请求上达到文件/任何I / O的开销,您可以在块中分配ID,将块的端点回送到存储。

所以它最终成为:

  • 为每个服务器提供ID
  • 在服务器上存储存储当天最后分配的值(例如文件)
  • 让ID分配器在块中工作(一次10个ID,100,无论如何)
  • 分配一个块:
    • 读取文件,写回一个由blocksize增加的数字
  • 使用块中的ID
  • ID将是,例如12000000027,用于服务器#12分配的第28个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(真随机   数字生成器通过大气噪​​声或生成随机性   光子发射)。

我认为如果你得到其中一个并将其与时间戳结合起来,你应该得到你想要的东西。