UNIQUE IDENTIFIER - SERVLETS/EJB

Discussion in 'Java' started by crazygrape, Jun 9, 2004.

  1. crazygrape

    crazygrape Guest

    Hi,

    I'm trying to create a unique identifier (e.g. a serially indexed invoice
    number) in servlets before persisting it to a database. Does anyone know of
    how I should be creating a singleton that delivers me such a number?

    I'm thinking that creating a static class which, when empty, fetches a last
    number of the database, then increments it everytime a method is called ...
    but in that model, what happens when you scale sideways (by clustering
    tomcats?).

    Thanks in advance.

    crazygrape
    crazygrape, Jun 9, 2004
    #1
    1. Advertising

  2. crazygrape

    Sudsy Guest

    crazygrape wrote:
    > Hi,
    >
    > I'm trying to create a unique identifier (e.g. a serially indexed invoice
    > number) in servlets before persisting it to a database. Does anyone know of
    > how I should be creating a singleton that delivers me such a number?

    <snip>

    You already have a database available so look into sequences. The
    database will provide the synchronization and you don't have to
    worry about skipping or duplicating numbers, persisting to a file,
    etc.
    Sudsy, Jun 9, 2004
    #2
    1. Advertising

  3. crazygrape

    crazygrape Guest

    Hi,

    I'm trying to avoid calling the DB until I persist the object as I'd like to
    use the database resources sparingly.

    I'm also worried that if I do a simple fetch of max(invoicenumber),
    increment it and there are two concurrent invoices being looked at, then
    only the first one would persist to the DB, and the 2nd would suffer a
    unique constraint error.

    Is there another way I can generate a sequential number in memory
    beforehand?

    Crazygrape


    "Sudsy" <> wrote in message
    news:...
    > crazygrape wrote:
    > > Hi,
    > >
    > > I'm trying to create a unique identifier (e.g. a serially indexed

    invoice
    > > number) in servlets before persisting it to a database. Does anyone

    know of
    > > how I should be creating a singleton that delivers me such a number?

    > <snip>
    >
    > You already have a database available so look into sequences. The
    > database will provide the synchronization and you don't have to
    > worry about skipping or duplicating numbers, persisting to a file,
    > etc.
    >
    >
    crazygrape, Jun 9, 2004
    #3
  4. crazygrape

    Sudsy Guest

    crazygrape wrote:
    > Hi,
    >
    > I'm trying to avoid calling the DB until I persist the object as I'd like to
    > use the database resources sparingly.
    >
    > I'm also worried that if I do a simple fetch of max(invoicenumber),
    > increment it and there are two concurrent invoices being looked at, then
    > only the first one would persist to the DB, and the 2nd would suffer a
    > unique constraint error.


    Hence my suggestion. Here's what I would do (using Oracle):
    - create sequence <sequence_name> start with <initial_value>;
    - every time you require a new, unique value execute a query
    like this:
    select <sequence_name>.nextval from dual;


    > Is there another way I can generate a sequential number in memory
    > beforehand?


    Yes, but then you're going to have to address synchronization and
    persistence yourself. Some tricky stuff there, analyzing failure
    modes and other gnarly possibilities, which is why I prefer to have
    the database handle it.
    Sudsy, Jun 9, 2004
    #4
  5. crazygrape

    Chris Smith Guest

    crazygrape wrote:
    > I'm also worried that if I do a simple fetch of max(invoicenumber),
    > increment it and there are two concurrent invoices being looked at, then
    > only the first one would persist to the DB, and the 2nd would suffer a
    > unique constraint error.


    Sequences solve that problem... but, since you want an application-level
    answer, here it is:

    > Is there another way I can generate a sequential number in memory
    > beforehand?


    Here's some simple code to get unique numbers from an application:

    class NumberGenerator
    {
    private long next;

    public NumberGenerator(long start)
    {
    this.next = start;
    }

    public synchronized long nextNumber()
    {
    return next++;
    }
    }

    This is a decent basis for a solution to your problem. Note the word
    "synchronized" in the declaration for nextNumber(); it's very important.

    Now you need to worry about how to make it persistent across invocations
    of the app. The easiest way to do this is to use a backing file, and be
    very careful to think about error conditions. For example:

    class NumberGenerator
    {
    private static final int SAVE_INTERVAL = 1000;

    private File backing;
    private long lastSave;
    private long next;

    public NumberGenerator(File backing)
    throws IOException
    {
    this.backing = backing;
    DataInputStream in = new DataInputStream(
    new FileInputStream(backing);
    try
    {
    this.lastSave = in.readLong();
    this.next = lastSave + SAVE_INTERVAL;
    }
    finally
    {
    in.close();
    }
    }

    public synchronized long nextNumber()
    throws IOException
    {
    if (next - lastSave >= SAVE_INTERVAL)
    {
    FileOutputStream out = new FileOutputStream(backing);
    try
    {
    new DataOutputStream(out).writeLong(next);
    out.getFD().sync();
    lastSave = next;
    }
    finally
    {
    out.close();
    }
    }

    return next++;
    }
    }

    That will fail and prevent you from adding new records for as long as
    the file is unavailable (disk space, device failure, or whatever), which
    is what you want.

    The final challenge is to make this functionality usable in a multi-app
    environment. As it is, this would only work if you only needed to
    insert records from one onstance of one application, ever. Should you
    ever want to start a second copy of this application (for load balancing
    and such) or insert records from a different application, you'd be out
    of luck. One simple (though not ideal) solution would be to expose an
    interface to this functionality via RMI, and start it at one canonical
    location on your server.

    All this has the unfortunate side effect of introducing an extra single
    point of failure into your system, but that's a natural effect of using
    an extra system besides the database for data-related operations.
    Furthermore, while most databases have replication solutions available,
    you don't. This could be made redundant and distributed, but that's
    more complex that I would write just to post to USENET. Be ready for at
    least a week of development to get something like this working, even for
    your simple ID generator, and more if you've never done it before.

    At this point, I'd be surprised if you keep up your quest for local key
    generation... but this is the reason people are suggesting that you use
    the database.

    --
    www.designacourse.com
    The Easiest Way to Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
    Chris Smith, Jun 9, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page