Gary Albers@TIMEWEB
04/28/2000 02:51 PM
Hi folks,
I have a solution that I am using for generating unique primary keys
that I would like to put out on the table for review.
I have not seen a solution exactly like this proposed anywhere, so
I would really appreciate the feedback. And who knows, if it holds
up to scrutiny, it might be useful.
GOALS:
I wanted the object that generated a new primary key to:
- be a Singleton service, even across a cluster of EJB servers.
- be able to be cached so that most of the time, it's work would be
done in memory and not require a hit to the database.
- be synchronized so that two beans of the same type asking for a
new key at the same moment would get two unique values
correctly.
- be portable across EJB servers and across RDBMS vendors.
DESIGN:
I created a base class EntityBean called AbstractSingleton. My
primary key service called NextPKServer extends AbstractSingleton.
I have other services that also extend AbstractSingleton. Each one
is mapped to a table called SingletonServers and has an internal
constant value that is it's unique key to the SingletonServers table.
Making the NextPKServer, (and all extenders of AbstractSingleton),
an entity bean with only one key value forces the singleton model.
The EJB server provides the single threaded access to the one
instance, even across a cluster, and also manages the caching of
the bean.
Extenders of the AbstractSingleton do not have a create() in the
Home interface. A Factory class I call EJBFactory is used
to obtain a reference to any of the singleton service beans.
The EJBFactory uses all static methods and variables so it
also acts as a singleton class within the JVM it is running in.
Internally, EJBFactory uses the javax.ejb.Handle class to make
subsequent access to each service more efficient.
All of my entity beans that use this pattern extend a base class called
AbstractEntityBean which has the following:
- A primary key class that uses a single Long value. This gives all
my EntityBeans an easy to deal with, unique Object ID (OID).
- A create() & postCreate() method that uses another method called
createPrimaryKey(). This makes primary key generation consistent,
automatic, and does not have to be coded for each bean by all our
developers.
- A deployment descriptor that defines an <env-entry> that contains
the SQL used to determine the current maximum value for the primary
key column. If your project naming conventions allow you to name
the table the same as the object name and the columns the same as
the attribute names then it is not necessary to get the SQL from each
bean, it could be determined from a single configuration file.
- The createPrimaryKey() method has this code:
MyPrimaryKey pk = EJBFactory.getNextPKServer().
getNextPKFor(objectName, maxPKSql);
Inside the NextPKServer, here is the approach I use for generating
the next primary key value for each bean:
- Each request for a unique key provides two parameters:
1 - An object name
2 - A SQL string that is used to initially obtain the current maximum
value for the primary key of that object.
- A Map is used to store the object names and their associated max key
value. The Map is also stored in JNDI, so if the NextPKServer were
passivated, the values are still in memory.
- When a new key is requested, I go through these steps:
1 - Get Map.
2 - If not present yet, get it from JNDI.
3 - If not in JNDI, create it.
4 - Look for object name in Map.
5 - If found, increment value, store new value in map, and return
value.
6 - If not found, execute SQL to determine current max value.
Increment value, store value in Map, and return value.
ASSUMPTIONS IN MY IMPLEMENTATION:
- The JNDI server and all implementors of AbstractSingleton must run
within the same VM. Within a clustered environment, the singleton
services would have to be configured to run in the same JVM that the
JNDI server is running.
- When objects are put into JNDI, they are NOT serialized (i.e. passed
by value). In other words, the singleton server's reference to the
Map it put into JNDI and the reference JNDI holds is to the exact
same instance of the object.
If either of these two assumptions are not valid, then the singleton server
would need to put a new copy of it's Map back into JNDI each time it
updated a value in it.
BENEFITS:
- This approach means that as long as the server where the
singleton server and JNDI are running stays up, it will only require
one hit to the database per table to determine a primary key for an
EntityBean for the rest of the life of the JVM. All subsequent accesses
will be in memory processing.
- Simple for client to use.
- Portable
- It is flexible. This design has several points where changes could
be made without breaking the overall design:
* The EJBFactory could be enhanced if if needed to be smarter about
the type or instance of NextPKServer it returned.
* The NextPKServer could be changed to use a different storage
mechanism other than JNDI for storage of it's Map. (I am
considering using a JavaSpace if JNDI doesn't work out in a cluster
or under different EJB servers.)
* The NextPKServer could be changed to use some other algorithm
for determining the next primary key. (RDBMS specific sequence
generator, stored procedure, etc.)
CONCLUSION:
If you've read this far, I salute you.
I would really appreciate any comments or feedback you have on
this design.
If you have questions or would like more details, let me know.
Thanks,
Gary Albers
[EMAIL PROTECTED]
Anders Bengtsson <[EMAIL PROTECTED]> on 04/25/2000 04:22:17 AM
To: Orion-Interest <[EMAIL PROTECTED]>
cc: (bcc: Gary Albers/DDI)
Subject: Generating primary keys in CMP?
Hello,
I'm looking for a way to generate primary keys for my container managed
entity beans.
For bean managed persistance you would simply use the functions that
your DBMS provides, like sequences or auto-increased columns. But how do
I do this with CMP beans? In books and example code everyone avoids the
subject entirely, with
create(int id)
as the creation method.
A solution I've seen suggested is to use a separate session bean to
generate unique integers, but they are generally a mess to implement and
use. So what I'm looking for is something better than that.
The J2EE servers based on object databases (GemStone/J at least) has an
id generator "for free". But it seems this shouldn't be impossible with
relational DBMSes. I would guess that it could be done by the CMP
container, possibly by using DBMS-dependent plugins for different id
generator implementations?
Anyway, if this isn't possible I'm looking for a good implementation of
a session bean based id generator...
/Anders
________________________________________________________________________
A n d e r s B e n g t s s o n [EMAIL PROTECTED]
http://www.natakademin.se/