UNIQUE IDENTIFIER - SERVLETS/EJB

C

crazygrape

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
(e-mail address removed)
 
S

Sudsy

crazygrape said:
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.
 
C

crazygrape

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
(e-mail address removed)
 
S

Sudsy

crazygrape said:
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:
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.
 
C

Chris Smith

crazygrape said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top