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