Generating Primary Keys


The ToDo application uses UUID-like primary keys created by code that XDoclet generated. We chose this method because it was an easy and portable method of generating primary keys without any dependencies on JBoss. As you've seen, it works fine, but there are many other options besides pseudo-UUIDs.


Note: Many projects add a keygenerated session bean for this, but it is much nicer if you can use a transparent service provided by the application server.

We easily could have chosen another method, such as sequence tables or auto-increment columns on the database. There are many possibilities, but they all require extra code to be written, code that potentially has hard dependencies on the database type. We would prefer to keep that code outside of the application, if possible.

JBoss provides a way to attach a primary key generator to an entity bean to do exactly that. The bean can completely ignore primary key generation and leave the key generation policy as a deployment-time configuration option.

How do I do that?

When we wrote the ToDo application, we decided to use UUID strings as key objects. That's an acceptable decision, especially considering our goal to create an application that can be deployed with no external configuration, but it limits the key generation options. Most key generation strategies use numeric keys instead of string-based keys. Instead of limiting the discussion to text keys, we are going to rewrite the application to use numeric primary keys.

This rewrite is not as big as you might expect, since XDoclet manages most of the EJB tier for you. You need to change the id fields to be of type Integer, like this:

     /**      * @ejb.pk-field      * @ejb.persistence      * @ejb.interface-method       */     public abstract Integer getId(  );     public abstract void setId(Integer id); 


Note: Notice that the ejbCreate method doesn't set the ID anymore. JBoss will fill in the value, just as it is doing for the user and started-Date fields, which are filled in from the audit data.

Some additional support methods, such as the ejbCreate method on TaskBean, also need to change signatures:

     /** @ejb.create-method */     public Intenger ejbCreate(String name)         throws CreateException     {         setName(name);         return null;     } 

The changes don't ripple far. We've provided an alternate version of the ToDo application in the todo2 directory that contains the minimal changes to the session façade and to the JSF commands for this.

With that refactoring out of the way, let's see how to get JBoss to fill in the ID values. Key generation is accomplished by associating an entity command to an entity bean. The job of the entity command is to insert a newly created bean into the database while figuring out what the primary key should be.

In this example, you'll use a simple auto increment column in the database. In Hypersonic, whenever a row is inserted into a table with an identity column, Hypersonic will generate the next sequential key number and make it available to the client through a subsequent CALL IDENTITY( ) statement.

The entity command that understands how to generate sequential keys is hsqldb-fetch-key. To set this as the entity command for all entity beans, add an entity-command declaration to the defaults section of jbosscmp-jdbc.xml:

     <defaults>         <create-table>true</create-table>         <alter-table>true</alter-table>         <remove-table>true</remove-table>         <entity-command name="hsqldb-fetch-key" />     </defaults> 

Now, mark each primary key field as an auto-increment field:

     <entity>         <ejb-name>Task</ejb-name>         <table-name>TODO_TASK</table-name>         <cmp-field>             <field-name>id</field-name>             <column-name>TASK_ID</column-name>             <auto-increment />         </cmp-field>         <!-- other CMP fields -->     </entity> 

That's all there is to it. You can deploy the application from the todo2 directory using the same build options as for the original application:

     [todo2]$ ant main deploy 


Note: One advantage that numeric keys have over UUID keys is that simple numeric keys are much more readable. Looking over the TODO_ TASK table is so much easier now.

When you deploy the application, JBoss will create the new schema, marking the primary key as an identity column:

     CREATE TABLE TODO_TASK      (         TASK_ID INTEGER NOT NULL IDENTITY,          TASK_NAME VARCHAR(256),          TASK_USER VARCHAR(256),          TASK_START TIMESTAMP,          TASK_END TIMESTAMP,          CONSTRAINT PK_TODO_TASK PRIMARY KEY (TASK_ID)     ) 

Try creating a few tasks and watch the IDs in the TODO_TASK table increment with each newly created task.

What just happened

You saw how to enable primary key generation in JBoss. All you had to do was to select the appropriate entity command and attach it to the application. You also could have associated the entity command with a specific bean, but generally you'll want key generation to work the same for all the entity beans in your application.

What about...

...other databases?

Each database supports different mechanisms for key generation. For MySQL, mysql-get-generated-keys makes use of the getGeneratedKeysfunction. The oracle-sequence entity command understands how to work with Oracle sequences. Check the standardjbosscmp-jdbc.xml file for the full set of database-specific entity commands.

...what about using your own key generator?

It is possible to write your own entity command, but that is no small task. Instead, you should look at the key-generator entity command. It interfaces with the JBoss key generator factory MBean, which you can easily replace with a factory that provides your own custom key generator.



JBoss. A Developer's Notebook
JBoss: A Developers Notebook
ISBN: 0596100078
EAN: 2147483647
Year: 2003
Pages: 106

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net