Section 9.1, “Transaction Types” introduced optimistic
		transactions.  In order to prevent one optimistic transaction from
		blindly overwriting the changes made by a concurrent transaction,
		JDOR versions your objects.  The version element
		dictates what form this versioning takes.
		
		The version element appears just after the
		inheritance element in a mapping document.  Only
		the least-derived mapped classes in an inheritance hierarchy use the
		version element.  The element has the following 
		attributes:	
		
				
				strategy: The version strategy.  We review
				the standard JDO strategies in the following sections.
				Vendors may define additional non-standard strategies.
				
| ![[Note]](img/note.gif) | Note | 
|---|---|
| Kodo does not define any non-standard version strategies, but does allow you to plug in custom strategies of your own. The Reference Guide's Section 7.10, “Custom Mappings” documents version customization in detail. Kodo also allows you to define multiple lock groups for fine-grained control over optimistic versioning. See Section 5.8, “Lock Groups” in the Reference Guide for more information on lock groups. | 
				
				column: The column that holds the 
				version value.  Not all version strategies require a column.
				
				As with other elements, the column attribute
				can be replaced with a nested column element.
				
			As its name implies, the none version strategy 
			performs no versioning at all.  Using concurrent optimistic 
			transactions under this strategy is dangerous.
			
			The version-number strategy stores a 
			monotonically increasing version number in the column indicated by
			the column attribute/element.  When a dirty
			object's database record is being updated, the JDOR implementation 
			checks its in-memory version number against the database version 
			number.  If the database version is higher, the implementation 
			knows that another transaction has modified the object since the 
			current PersistenceManager last read its 
			state, and it aborts the transaction to preserve data integrity.  
			If the version number is the same, on the other hand, the 
			implementation increments the number and proceeds with the flush.
			
			The version-number strategy is the fastest,
			most efficient, and most accurate version strategy.  Its only
			drawback is that it requires a dedicated database column. If you 
			are mapping to legacy tables you might not be able to use it.
			
			The date-time strategy is exactly like the
			version-number strategy, but it timestamps
			each update rather than storing an increasing integer.  This 
			strategy is mainly present to support existing tables that use 
			time-based versioning.  We do not recommend it for new schemas,
			since it is theoretically possible for two updates to happen so 
			close together that they have the same timestamp.
			The version-number strategy is a 
			better choice.  In addition to being slightly more efficient, 
			it does not suffer from these sorts of timing failures.
			
			The state-comparison version strategy does not
			require a database column.  It works by comparing the last-read
			values of your object with the database on flush.  If any values 
			in the database don't match the recorded last-read value, then
			some other transaction must have concurrently modified the data, 
			and the flush is aborted.  
			
			Unfortunately, the state-image strategy is much 
			more memory-hungry than other strategies, because the JDOR runtime 
			has to store the last-read values of all modified fields.  It also 
			results in more complex UPDATE SQL statements as
			the JDOR implementation verifies that no column has been changed by
			a concurrent transaction.  Finally, it suffers from the following
			limitations:
			
					Only simple, exact field values can be used in state 
					comparisons.  If a commit only changes a 
					float or Collection 
					field, subsequent commits will not detect any difference
					in the object's version, because these fields are not
					compared.  Thus it is possible for one transaction to
					unknowingly overwrite another.
					
					If two concurrent transactions make changes to fields that
					reside in a disjoint set of tables, the second transaction
					may overwrite the first.  For example, if one transaction
					modifies a TrialSubscription
					instance by only changing fields mapped to 
					CNTRCT.SUB, and a concurrent transaction modifies
					the same instance but only changes fields mapped to
					CNTRCT.TRIAL_SUB, one transaction might 
					overwrite the other.
					
			Due to these shortcomings, we only recommend using the 
			state-comparison strategy when performing optimistic	
			transactions on legacy tables without a version column.
			
Here is our model with version columns added:

			And here is our updated mapping data.  We made sure that all
			version strategies are represented for illustrative purposes.  Note
			that as an unmapped subclass-table type, 
			Contract does not declare a version.  Its
			direct subclasses Subscription and
			LineItem, however, each define version 
			mappings.  TrialSubscription does not declare
			an additional version on its CNTRCT.TRIAL_SUB
			table, because it joins down to its superclass table.  We have
			also continued to consolidate our mappings; this document leaves out
			default inheritance and discriminator mappings.		
			
Example 15.10. Version Mapping
<?xml version="1.0"?>
<orm>
    <package name="org.mag">
        <sequence name="ArticleSeq" datastore-sequence="ART_SEQ"/> 
        <class name="Magazine" table="MAG">
            <version column="VERS" strategy="version-number"/>
            <field name="isbn">
                <column name="ISBN" jdbc-type="char" length="15"/>
            </field>
            <field name="title" column="TITLE"/>
            ...
        </class>
        <class name="Article" table="ART">
            <version column="UPD" strategy="date-time"/>
            <field name="id" column="ID"/>
            ...
        </class>    
    </package>
    <package name="org.mag.pub">
        <sequence name="AuthorSeq" factory-class="Author$SequenceFactory"/>
        <class name="Company" table="COMP">
            <datastore-identity column="CID" strategy="autoassign"/>
            <version strategy="none"/>
            ...
        </class>    
        <class name="Author" table="AUTH">
            <datastore-identity sequence="AuthorSeq">
                <column name="AID" sql-type="INTEGER64"/>
            </datastore-identity>
            <inheritance>
                <discriminator column="CLS" strategy="class-name"/>
            </inheritance>
            <version strategy="state-comparison"/>
            ...
        </class>
    </package>
    <package name="org.mag.subscribe">
        <sequence name="ContractSeq" strategy="transactional"/> 
        <class name="Contract">
            <inheritance strategy="subclass-table"/>
            ...
        </class>
        <class name="Subscription" table="CNTRCT.SUB">
            <inheritance>
                <discriminator value="1">
                    <column name="TYPE" jdbc-type="tinyint"/>
                </discriminator>
            </inheritance>
            <version column="VERS" strategy="version-number"/>
            <field name="Contract.id" column="ID"/>
            ...
        </class>
        <class name="LifetimeSubscription">
            <inheritance>
                <discriminator value="2"/>
            </inheritance>
            ...
        </class>
        <class name="TrialSubscription" table="CNTRCT.TRIAL_SUB">
            <inheritance strategy="new-table">
                <join column="ID"/>
                <discriminator value="3"/>
            </inheritance>
            ...
        </class>
        <class name="Subscription$LineItem" table="CNTRCT.LINE_ITEM">
            <version column="VERS" strategy="version-number"/>
            <field name="Contract.id" column="ID"/>
            ...
        </class>
    </package>
</orm>
|    |