License     Codehaus     OpenEJB     OpenJMS     OpenORB     Tyrex     

Old releases
  General
  Release 1.3
  Release 1.3rc1
  Release 1.2

Main
  Home
  About
  Features
  Download
  Dependencies
  Reference guide
  Publications
  JavaDoc
  Maven 2 support
  Maven 2 archetypes
  DTD & Schemas
  Recent HTML changes
  News Archive
  RSS news feed
  Project Wiki

Development/Support
  Mailing Lists
  SVN/JIRA
  Contributing
  Support
  Continuous builds
  Prof. services

Related projects
  Spring ORM support
  Spring XML factories
  WS frameworks

XML
  XML

XML Code Generator
  XML Code Generator

JDO
  Introduction
  First steps
  Using JDO
  JDO Config
  Types
  JDO Mapping
  JDO FAQ
  JDO Examples
  JDO HOW-TOs
  Tips & Tricks
  Other Features
  JDO sample JAR

Tools
  Schema generator

Advanced JDO
  Caching
  OQL
  Trans. & Locks
  Design
  KeyGen
  Long Trans.
  Nested Attrs.
  Pooling Examples
  LOBs
  Best practice

DDL Generator
  Using DDL Generator
  Properties
  Ant task
  Type Mapping

More
  The Examples
  3rd Party Tools
  JDO Tests
  XML Tests
  Configuration
 
 

About
  License
  User stories
  Contributors
  Marketplace
  Status, Todo
  Changelog
  Library
  Contact
  Project Name

  



Castor JDO Key Generator Support


Introduction
MAX key generator
HIGH-LOW key generator
UUID key generator
IDENTITY key generator
SEQUENCE key generator


Introduction

The key generator gives a possibility to generate identity field values automatically. During create the value of the identity field is set to the value obtained from the key generator. Different algorithms may be used here, both generic and specific for database server.

The key generator for the given class is set in the mapping specification file (mapping.xml), in the key-generator attribute of the class element, for example:

  <class name="myapp.ProductGroup"
         identity="id" key-generator="MAX">
    <field name="id">
    </field>
  </class>
         

The following key generator names are supported in Castor 1.0:
MAX"MAX( pk ) + 1" generic algorithm
HIGH-LOWHIGH-LOW generic algorithm
UUIDUUID generic algorithm
IDENTITYSupports autoincrement identity fields in Sybase ASE/ASA, MS SQL Server, MySQL and Hypersonic SQL
SEQUENCESupports SEQUENCEs in Oracle, PostgreSQL, Interbase and SAP DB

Some of these algorithms have parameters, which can be specified in the key-generator element of the mapping specification file, for example:

  <key-generator name="HIGH-LOW">
    <param name="table" value="SEQ"/>
    <param name="key-column" value="SEQ_TableName"/>
    <param name="value-column" value="SEQ_MaxPKValue"/>
    <param name="grab-size" value="1000"/>
  </key-generator>

  <class name="myapp.ProductGroup"
         identity="id" key-generator="HIGH-LOW">
    <field name="id">
    </field>
  </class>
         

It is possible to create several key generators with the same algorithms but diffent parameters. In this case you have to specify the alias attribute in the key-generator element, for example:

  <key-generator name="SEQUENCE" alias="A">
    <param name="sequence" value="a_seq"/>
  </key-generator>

  <key-generator name="SEQUENCE" alias="RETURNING">
    <param name="sequence" value="b_seq"/>
    <param name="returning" value="true"/>
  </key-generator>

  <class name="myapp.ProductGroup"
         identity="id" key-generator="RETURNING">
    <field name="id">
    </field>
  </class>
         

Below all supported key generators a described in details.

MAX key generator

MAX key generator fetches the maximum value of the primary key and lock the record having this value until the end of transaction. Then the generated value is set to (MAX + 1). Due to the lock concurrent transactions which perform insert to the same table using the same key generator algorithm will wait until the end of the transaction and then will fetch new MAX value. Thus, duplicate key exception is almost impossible (see below). Note, that it is still possible to perform multiple inserts during the same transaction.

There is one "singular" case of this algorithm: the case when the table is empty. In this case there is nothing to lock, so duplicate key exception is possible. The generated value in this case is 1.

This algorithm has no parameters. Primary key must have type integer, bigint or numeric.

HIGH-LOW key generator

This key generator uses one of the variants of the generic HIGH-LOW algorithm. It is needed a special auxiliary table ("sequence table") which has the unique column which contains table names (of the type char or varchar) and the column which is used to reserve values of the primary keys (of the type integer, bigint or numeric). The key generator seeks for the given table name, reads the last reserved value and increases it by some number N, which is called "grab size". Then the lock on the auxiliary table is released, so that concurrent transactions can perform insert to the same table. The key generator generates the first value from the grabbed interval. During the next (N - 1) invocations it generates the other grabbed values without database access, and then grabs the next portion. Note, that the auxiliary table must be in the same database as the table for which key is generated. So, if you work with multiple databases, you must have one auxiliary table in each database.

If the grab size is set to 1, the key generator each time stores the true maximum value of the primary key to the auxiliary table. In this case the HIGH-LOW key generator is basically equivalent to the MAX key generator. On you want to have LOW part of the key consisting of 3 decimal digits, set the grab size to 1000. If you want to have 2 LOW bytes in the key, set the grab size to 65536. When you increase the grab size, the speed of key generation also increases because the average number of SQL commands that are needed to generate one key is (2 / N). But that average number of key values that will be skipped (N / 2) also increases.

The HIGH-LOW key generator has the following parameters:
tableThe name of the special sequence table.Mandatory
key-columnThe name of the column which contains table namesMandatory
value-columnThe name of the column which is used to reserve primary key valuesMandatory
grab-sizeThe number of new keys the key generator should grab from the sequence table at a time. Optional, default="10"
same-connectionTo use the same Connection for writing to the sequence table, values: "true"/"false". This is needed when working in EJB environment, though less efficient. Optional, default="false"
globalTo generate globally unique keys, values: "true"/"false". Optional, default="false"

If the parameter "global" is set to "true", the sequence table contains only one row with "<GLOBAL>" instead of the table name. This row serves for all tables.

Don't forget to set same-connection="true" if you are working in EJB environment!

Note, that the class HighLowKeyGenerator is not final, so you can extend it in order to implement other variants of HIGH-LOW algorithm (for example, HIGH/MID/LOW or char key values).

UUID key generator

This key generator generates global unique primary keys. The generated key is a combination of the IP address, the current time in milliseconds since 1970 and a static counter. The complete key consists of a 30 character fixed length string.

This algorithm has no parameters. Primary key must have type char, varchar or longvarchar.

IDENTITY key generator

IDENTITY key generator can be used only with autoincrement primary key columns (identities) with Sybase ASE/ASA, MS SQL Server, MySQL and Hypersonic SQL. After the insert the key generator selects system variable @@identity which contains the last identity value for the current database connection. In the case of MySQL and Hypersonic SQL the system functions LAST_INSERT_ID() and IDENTITY() are called, respectively.

This algorithm has no parameters.

SEQUENCE key generator

The SEQUENCE key generator type is supported in conjunction with the following DBMS: Derby, Interbase, Oracle, PostgreSQL, and SAP DB. It generates keys using database sequence objects.

The key generator has the following parameters:
sequenceThe name of the sequence Optional, default="{0}_seq"
returningRETURNING mode for Oracle8i, values: "true"/"false" Optional, default="false"
incrementIncrement for Interbase Optional, default="1"
triggerAssume that there is a trigger that already generates key. Values: "true"/"false" Optional, default="false"

Usually one sequence is used for one table, so in general you have to define one key generator per table. But if you use some naming pattern for sequences, you can use one key generator for all tables. For example, if you always obtain sequence name by adding "_seq" to the name of the correspondent table, you can set "sequence" parameter of the key generator to "{0}_seq" (the default value). In this case the key generator will use sequence "a_seq" for table "a", "b_seq" for table "b", etc. Castor also allows for inserting the primary key into the sequence name as well. This is accomplished by including the {1} tag into the "sequence" parameter. Example: "{0}_{1}_seq"

Actually the SEQUENCE key generator is "4 in 1". With PostgreSQL it performs "SELECT nextval(sequenceName)" before INSERT and produces identity value that is then used in INSERT. Similarly, with Interbase it performs "select gen_id(sequenceName, increment) from rdb$database" before INSERT. With Oracle by default (returning=false) and with SAP DB it transforms the Castor-generated INSERT statement into the form "INSERT INTO tableName (pkName,...) VALUES (sequenceName.nextval,...)" and after INSERT it performs "SELECT seqName.currval FROM tableName" to obtain the identity value. With Oracle8i it is possible to use more efficient RETURNING mode: to the above INSERT statement is appened "RETURNING primKeyName INTO ?" and the identity value is fetched by Castor during INSERT, so that only one SQL query is needed.

In case when your table has an on_Insert trigger which already generates values for your key, like the following Oracle example:

   create or replace trigger "trigger_name"
   before insert on "table_name" for each row 
   begin 
      select "seq_name".nextval into :new."pk_name" from dual;
   end;
          

you may set the "trigger" parameter to "true". This will prevent the "Sequence_name".nexval from being pulled twice (first time in the insert statement (see above), then in the trigger). Also usefull in combination with the "returning" parameter set to "true" for Oracle (in this case you may not specify the sequence name).

 
   
  
   
 


Copyright © 1999-2005 ExoLab Group, Intalio Inc., and Contributors. All rights reserved.
 
Java, EJB, JDBC, JNDI, JTA, Sun, Sun Microsystems are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and in other countries. XML, XML Schema, XSLT and related standards are trademarks or registered trademarks of MIT, INRIA, Keio or others, and a product of the World Wide Web Consortium. All other product names mentioned herein are trademarks of their respective owners.