Source code of all SequenceManager
implementations can be
found in org.apache.ojb.broker.util.sequence
package.
If you still think something is missing you can just write your own
sequence manager implementation.
High/Low sequence manager
Per default OJB internally uses a High/Low algorithm based sequence manager
for the generation of unique ids, as described in
Mapping Objects To Relational Databases.
This implementation is called
ojb.broker.util.sequence.SequenceManagerHighLowImpl
and is able to generate IDs unique to a given object and
all extent objects declarated in the objects class descriptor.
If you ask for an uid using an interface with several
implementor classes, or a baseclass with several subclasses the returned
uid have to be unique accross all tables representing objects of the
extent in question (more see here).
It's also possible to use this implementation in a global mode, generate
global unique id's.
 |  |  |
 |
<sequence-manager className=
"org.apache.ojb.broker.util.sequence.SequenceManagerHighLowImpl">
<attribute attribute-name="grabSize" attribute-value="20"/>
<attribute attribute-name="globalSequenceId"
attribute-value="false"/>
<attribute attribute-name="globalSequenceStart"
attribute-value="10000"/>
<attribute attribute-name="autoNaming"
attribute-value="true"/>
</sequence-manager>
|  |
 |  |  |
With property grabSize
you set the size of the assigned ids
(default was 20).
If property globalSequenceId
was set true
you will
get global unique ids over all persistent objects. Default was false
.
The attribute globalSequenceStart
define the start value of the
global id generation (default was 10000).
This sequence manager implementation supports user defined sequence-names
to manage the sequences.
The attribute autoNaming
define if sequence names should be build
automatic if none found in field-descriptor
.
If set 'true' OJB try to build a
sequence name automatic if none found in field-descriptor
and set this name as sequence-name
in field-descriptor (see more).
If set 'false' OJB throws an exception
if none sequence name was found in field-descriptor (default was 'true').
Limitations:
- do not use in managed environments when connections were enlisted
in running transactions, e.g. when using DataSources of an application server
- if set connection-pool attribute 'whenExhaustedAction' to 'block' (wait for
connection if connection-pool is exhausted), under heavy load this sequence manager
implementation can block application.
- superfluously to mention, do not use if other non-OJB applications insert objects too
In-Memory sequence manager
Another sequence manager implementation is a In-Memory version
called ojb.broker.util.sequence.SequenceManagerInMemoryImpl
.
Only the first time an uid was requested for a object,
the manager query the database for the max value of the target
column - all following request were performed in memory. This
implementation ditto generate unique ids across all
extents, using the same mechanism as the High/Low implementation.
 |  |  |
 |
<sequence-manager className="org.apache.ojb.broker.util.
sequence.SequenceManagerInMemoryImpl">
<attribute attribute-name="autoNaming"
attribute-value="true"/>
</sequence-manager>
|  |
 |  |  |
For attribute autoNaming
see
This sequence manager implementation supports user defined sequence-names
to manage the sequences (see more) or if not
set in field-descriptor
it is done automatic.
This is the fastest standard sequence manager implementation, but
has some Limitations:
- do not use in clustered environments
- superfluously to mention, do not use (or handle with care) if other non-OJB
applications insert objects too
Database sequences based implementation
If your database support sequence key generation (e.g. Oracle, SAP DB, PostgreSQL)
you could use the SequenceManagerNextValImpl
implementation let
your database generate the requested ids.
 |  |  |
 |
<sequence-manager className="org.apache.ojb.broker.util.
sequence.SequenceManagerNextValImpl">
<attribute attribute-name="autoNaming"
attribute-value="true"/>
</sequence-manager>
|  |
 |  |  |
Attribute autoNaming
default was 'true'. If set 'true' OJB try to build a
sequence name automatic if none found in field-descriptor
and set this generated name as sequence-name
in field-descriptor.
If set 'false' OJB throws an exception
if none sequence name was found in field-descriptor, ditto
OJB does NOT try to create a database sequence entry when
for given sequence name no database sequence could be found.
When using this sequence manager it is possible
to define a sequence-name field-descriptor
attribute
in the repository file for each autoincrement/pk field. If you don't
specify a sequence name, the sequence manager try to
build a extent-aware sequence name on its own - except you set attribute
autoNaming
to 'false', then an exception will be thrown.
Keep in mind that in this case you are responsible to be aware of extents.
Thus you have to use the same sequence-name
attribute value
for all extents, even if the extents were mapped to different database tables.
See usage of the sequence-name
attribute:
 |  |  |
 |
<class-descriptor
class="org.apache.ojb.broker.sequence.SMDatabaseSequence"
table="SM_TAB_DATABASE_SEQUENCE"
>
<field-descriptor
name="seqId"
column="SEQ_ID"
jdbc-type="INTEGER"
primarykey="true"
autoincrement="true"
sequence-name="TEST_SEQUENCE"
/>
....
</class-descriptor>
|  |
 |  |  |
Limitations:
- none known
Database sequences based high/low implementation
Based on the sequence manager implementation described above, but
use a high/low algorithm to avoid database access.
 |  |  |
 |
<sequence-manager className="org.apache.ojb.broker.util.
sequence.SequenceManagerSeqHiLoImpl">
<attribute attribute-name="grabSize" attribute-value="20"/>
<attribute attribute-name="autoNaming"
attribute-value="true"/>
</sequence-manager>
|  |
 |  |  |
With the property
grabSize
you set the size of the assigned ids.
For attribute autoNaming
see.
This sequence manager implementation supports user defined sequence-names
to manage the sequences (see more) or if not
set in field-descriptor
it is done automatic.
Limitations:
- superfluously to mention, do not use (or handle with care) if other non-OJB
applications insert objects too
Oracle-style sequencing using stored procedure
(Thanks Ryan Vanderwerf et al.)
Ryan wrote:
This solution will give those seeking an oracle-style sequence generator
a final answer (Identity columns really suck). If you are using multiple
application servers in your environment, and your database does not
support read locking like Microsoft SQL Server, this is the only
safe way to guarantee unique keys (HighLowSequenceManager WILL
give out duplicate keys, and corrupt your data).
The SequenceManagerStoredProcedureImpl
implementation enabled database
sequence key generation in a Oracle-style for all databases (e.g. MSSQL, MySQL, DB2, ...).
First add a new table OJB_NEXTVAL_SEQ
to
your database.
 |  |  |
 |
CREATE TABLE OJB_NEXTVAL_SEQ
(
SEQ_NAME VARCHAR(150) NOT NULL,
MAX_KEY INTEGER,
CONSTRAINT SYS_PK_OJB_NEXTVAL PRIMARY KEY(SEQ_NAME)
)
|  |
 |  |  |
You will also need a stored procedure called ojb_nextval_proc
that will take care of giving you a guaranteed unique
sequence number.
Here is an example for the stored procedure you need to
use sequencing for MSSQL server:
 |  |  |
 |
CREATE PROCEDURE OJB_NEXTVAL_PROC
@SEQ_NAME varchar(150)
AS
declare @MAX_KEY BIGINT
-- return an error if sequence does not exist
-- so we will know if someone truncates the table
set @MAX_KEY = 0
UPDATE OJB_NEXTVAL_SEQ
SET @MAX_KEY = MAX_KEY = MAX_KEY + 1
WHERE SEQ_NAME = @SEQ_NAME
if @MAX_KEY = 0
select 1/0
else
select @MAX_KEY
RETURN @MAX_KEY
|  |
 |  |  |
You have to adapt this script if MSSQL was not used
(We are interested in scripts for other databases).
Last, enable this sequence manager implementation:
 |  |  |
 |
<sequence-manager className="org.apache.ojb.broker.util.
sequence.SequenceManagerStoredProcedureImpl">
<attribute attribute-name="autoNaming"
attribute-value="true"/>
</sequence-manager>
|  |
 |  |  |
For attribute autoNaming
see.
This sequence manager implementation supports user defined sequence-names
to manage the sequences (see more) or if not
set in field-descriptor
it is done automatic.
Limitations:
- currently none known
Microsoft SQL Server 'uniqueidentifier' type (GUID) sequencing
(Thanks Andrew Clute)
For those users you are using SQL Server 7.0 and up, the uniqueidentifier
was introduced, and allows for your rows Primary Keys to be GUID's that are
guaranteed to be unique in time and space.
However, this type is different than the Identity field type, whereas there
is no way to programmatically retrieve the inserted value. Most
implementations when using the u.i. field type set a default value of
"newid()". The SequenceManagerMSSQLGuidImpl class manages this process for
you as if it was any normal generated sequence/identity field.
Assuming that your PK on your table is set to 'uniqueidentifier', your
field-description would be the same as using any other SequenceManager:
 |  |  |
 |
<field-descriptor
name="guid"
column="document_file_guid"
jdbc-type="VARCHAR"
primarykey="true"
autoincrement="true"
/>
|  |
 |  |  |
Note that the jdbc-type is a VARCHAR, and thus the attribute (in this case
'guid') on your class should be a String (SQL Server does the conversion
from the String representation to the binary representation when
retrieved/set).
You also need to turn on the SequenceManager in your
jdbc-connection-descriptor like this:
 |  |  |
 |
<sequence-manager
className="org.apache.ojb.broker.util.sequence.SequenceManagerMSSQLGuidImpl"
/>
|  |
 |  |  |
Limitations:
-This will only work with SQL Server 7.0 and higher as the
uniqueidentifier type was not introduced until then.
This works well in situations where other applications might be updated the
database as well, because it guarantees (well, as much as Microsoft can
guarantee) that there will be no collisions between the Guids generated.
Identity based sequence manager
This sequence manager implementation supports database Identity columns
(supported by MySQL, MsSQL, HSQL, ...). When using identity columns we have to do
a trick to make the sequence manager work.
OJB identify each persistence capable object by a unique
ojb-Identity object. These ojb-Identity
objects were created using the sequence manager instance to
get UID's. Often these ojb-Identity objects were created before
the persistence capable object was written to database.
When using Identity columns it is not possible to retrieve the next
valid UID before the object was written to database. As recently as
the real object was written to database, you can ask the DB for the last
generated UID. Thus in SequenceManagerNativeImpl we have to do a trick and use
a 'temporary' UID till the object was written to database.
So, if it's possible try to avoid using Identity columns in your
database model. If not use this sequence manager implementation to
as a workaround for the Identity problem.
To enable this sequence manager implementation set in your
jdbc-connection-descriptor
:
 |  |  |
 |
<sequence-manager className="org.apache.ojb.broker.util.
sequence.SequenceManagerNativeImpl">
</sequence-manager>
|  |
 |  |  |
To declare the identity column in the repository.xml file add primarykey="true"
,
autoincrement="true"
and access="readonly"
to the field-descriptor
for your table's primary key identity column.
 |  |  |
 |
<field-descriptor
name="identifier"
column="NATIVE_ID"
jdbc-type="BIGINT"
primarykey="true"
autoincrement="true"
access="readonly"/>
|  |
 |  |  |
Limitations:
- The Identity columns have to start with value >= 1 and should
never be negative.
- Use of Identity columns is not extent aware (This may change in further versions).
More info here.