JDO


Java Data Objects (JDO) is not strictly a specification for O/R mapping but rather for general object persistence, covering any kind of backend data store, among them relational databases and object-oriented databases. Nevertheless, most JDO implementations do primarily target relational databases and can thus be classified as O/R mapping solutions.

JDO 2.0 builds on JDO 1.0, adding two important features: support for detached objects and dedicated support for O/R mapping. Detaching and reattaching objects is a very typical use case in web applications, which the JDO 1.0 API did not properly allow for (in contrast to other persistence solutions such as iBATIS SQL Maps and Hibernate). JDO implementations that access relational databases can support a variety of optional O/R mapping features, among those a common metadata format for mapping files.

JDOQL is a pure object query language in the tradition of ODMG's OQL, using a Java query API and Java-based criteria strings. The query facilities will become significantly extended in JDO 2.0, for example introducing textual queries as alternative style. Many current JDO implementations already support query extensions, mainly for access to relational databases.

JDO 1.0 implementations perform change detection in persistent objects through enhancing their byte code to make them implement the javax.jdo.PersistenceCapable interface. The byte code enhancer needs to be run as part of the application's build process. An enhanced class informs the JDO StateManager of any changes to its instance fields within a transaction; JDO always works with the instance fields, never with JavaBean property setters or getters. At transaction commit, the JDO PersistenceManager will flush the changes to the database, synchronizing the in-memory state with the database state.

JDO 2.0 downgrades byte code enhancement to one implementation option, removing the requirement for binary compatibility. JDO 2.0 implementations will then be free to choose any other strategy for change detection, such as snapshot comparisons as used by Hibernate and TopLink.

For further information on JDO's design and the current state of JDO, see www.jdocentral.com, the official online portal for JDO, which is backed by a large community of JDO vendors and affiliates.

Persistent Object Lifecycle

The most important characteristic of JDO is the strict lifecycle for persistent objects. By default, a persistent object will work only within an active JDO PersistenceManager; its instance fields will throw exceptions when accessed after the PersistenceManager has been closed. Furthermore, changes to persistent objects can be made only within a JDO transaction; there is no concept of non-transactional modifications. While this allows for very efficient change detection — essentially, every persistent field will notify the JDO StateManager of changes, rather than JDO looking for changed fields — it significantly restricts usage styles.

To work with persistent objects outside of an active JDO connection, they need to be made transient (JDO1.0) or detached (JDO 2.0) — usually an explicit step. A transient instance has lost its persistent identity, so can never be persisted again; this is the reason why JDO 2.0 introduces the concept of detachment and reattachment, allowing modification of objects outside of the JDO PersistenceManager that loaded them and then persist them in a new transaction (which is a typical use case in a web application).

Further options discussed for JDO 2.0 are auto-detach-on-close and auto-detach-on-serialization, which aim to remove the burden of explicit detachment. It is still unclear whether either or both of those will be part of the specification; certain JDO implementations already support such options as vendor-specific extensions. Persistent objects will then work in a managed fashion within a PersistenceManager, while still being usable outside of the PersistenceManager — containing a copy of their current state, without immediate change detection. This is similar to Hibernate's lenient lifecycle, where objects seam- lessly turn into a non-managed state as soon as the Hibernate Session is closed.

Unlike managed persistent instances, detached objects can be modified outside an active PersistenceManager and thus outside a JDO transaction. This will usually happen in a form work-flow: for example, in a web application or in a rich client. Such an object will then be passed back into the persistence layer again, getting reattached to a new JDO transaction, which will persist the current state as contained in the given instance. This corresponds to a saveOrUpdate operation in Hibernate.

Later, we will discuss a further area affected by the JDO lifecycle model: lazy loading.

DAO Implementation

Traditional JDO usage involves a resource factory, javax.jdo.PersistenceManagerFactory, which is used to open a single-threaded resource, javax.jdo.PersistenceManager, for each transaction or sequence of operations. This is roughly analogous to a Hibernate SessionFactory and a Hibernate Session, respectively; in many respects, Spring's support for Hibernate and JDO is very similar in this area.

In a Spring environment, provided convenience classes remove the burden of resource management from the application developer. Most importantly, JDO PersistenceManagers will automatically be synchronized with Spring transactions. In other respects, the usual conventions apply: DAO operations will throw Spring's generic DataAccessException, and DAOs are usually set up as beans in a Spring context.

The template class for data access operations is org.springframework.orm.jdo.JdoTemplate, working with JDO's PersistenceManager API underneath. It is typically used through the base class org.springframework.orm.jdo.support.JdoDaoSupport, which takes a JDO PersistenceManagerFactory instance as bean property and provides a JdoTemplate instance for it. (This is not a requirement, though: JdoTemplate can also be instantiated directly, just like HibernateTemplate.)

For example, the following is a rough version of a JDO-based implementation of PetClinic's DAO:

 public class JdoClinic extends JdoDaoSupport  implements Clinic {       public Collection getVets() throws DataAccessException {     return getJdoTemplate().find(         Vet.class, null, "lastName ascending, firstName ascending");   }       public Collection getPetTypes() throws DataAccessException {     return getJdoTemplate().find(PetType.class, null, "name ascending");   }       public Collection findOwners(String lastName) throws DataAccessException {     return getJdoTemplate().find(         Owner.class, "lastName == value", "String value", new Object[] {value});   }       ... }

As in the case of iBATIS and Hibernate, the provided convenience base class can easily be avoided: The implementation could implement its own setPersistenceManagerFactory method, preferably creating a shared JdoTemplate instance for the DAO.

Alternatively, a DAO implementation could also use the provided PersistenceManagerFactory instance directly, without Spring's JdoTemplate. However, this would involve manual handling of JDO PersistenceManagers, manual exception translation, and manual synchronization with Spring transactions; therefore, it is usually advisable to stick with JdoTemplate. If necessary, helpers for manual DAO implementations can be found in the org.springframework.orm.jdo.PersistenceManagerFactoryUtils class.

The operations defined on JdoTemplate basically correspond to operations on javax.jdo.PersistenceManager, however throwing Spring's DataAccessException rather than

JDOException, and participating in Spring-managed transactions (if any). Please refer to the JDO specification for details on the semantics of those operations. Note that JdoTemplate defines a variety of convenient find methods that are not directly available on a plain JDO PersistenceManager. In plain JDO, you always need to go through the JDOQL API.

As an alternative to invoking such operations on JdoTemplate itself, there is the option to implement an org.springframework.orm.jdo.JdoCallback that works directly on a given JDO PersistenceManager resource, via JdoTemplate's generic execute method. This is rarely necessary for typical one-line operations; however, complex JDO queries or processing operations should be implemented in a JdoCallback, in particular if they depend on getting executed on the same JDO PersistenceManager.

Like Hibernate, JDO has a special requirement for lazy loading. The JDO PersistenceManager that originally loaded the affected persistent objects needs to still be open to make lazy loading work. As JdoTemplate by default closes the JDO PersistenceManager at the end of each operation, returned objects are not capable of lazy loading. It is recommended that you execute such operations within transactions, which will keep the same JDO PersistenceManager open for the lifetime of the entire transaction. If you need lazy loading beyond the scope of your transactions, for example in web views, you need to resort to the Open PersistenceManager in View pattern (as described in detail in the "Open PersistenceManager in View" section).

All such a DAO needs to be able to work is a JDO PersistenceManagerFactory instance via the setPersistenceManagerFactory method. In the next section, you will see how to set up such an instance in a Spring context.

Setup in a Spring Context

In a Spring application context, a JDO implementation is usually set up via Spring's LocalPersistenceManagerFactoryBean, getting configured via specified JDO properties. The following is an example for the open source JDO implementation JPOX:

<bean      >   <property name="jdoProperties">     <props>       <prop key="javax.jdo.PersistenceManagerFactoryClass">         org.jpox.PersistenceManagerFactoryImpl       </prop>       <prop key="javax.jdo.option.ConnectionDriverName">         com.mysql.jdbc.Driver       </prop>       <prop key="javax.jdo.option.ConnectionURL">...</prop>       <prop key="javax.jdo.option.NontransactionalRead">true</prop>     </props>   </property> </bean> 

Alternatively, you can also use a standard jdo.properties file to configure your PersistenceManagerFactory, specifying the location as configLocation. Such file-based properties could also be mixed with LocalPersistenceManagerFactoryBean properties, with the latter taking precedence.

<bean      >   <property name="configLocation">     <value>classpath:jdo.properties</value>   </property> </bean>

An advantage of defining properties in the Spring context is that you can use placeholders for certain properties, linking in values from configuration properties files (via Spring's PropertyPlaceholderConfigurer mechanism, see Chapter 2). So even when loading configuration from a jdo.properties file, it is advisable to define such administrative properties on LocalPersistenceManagerFactoryBean in the Spring context.

A different configuration style is to set up the PersistenceManagerFactory implementation class itself as a Spring bean. JDO properties can usually be applied as bean properties, using the equivalent bean property names (which can be checked in the javadoc of your JDO implementation). Furthermore, it is usually possible to specify a Spring-managed JDBC DataSource as a JDO connection factory, which is important if you want to share a DataSource for both JDO and JDBC access code. Here's an example, again using JPOX:

<bean       >   <property name="connectionFactory">     <ref bean="dataSource"/>   </property>   <property name="nontransactionalRead">     <value>true</value>   </property> </bean>

Such a PersistenceManagerFactory implementation instance is a direct replacement for a LocalPersistenceManagerFactoryBean definition. These are simply two different ways to set up a JDO PersistenceManagerFactory, which can be chosen according to configuration requirements and the JDO implementation used.

For special setup requirements, it might also be necessary to use a custom subclass of LocalPersistenceManagerFactoryBean, overriding the newPersistenceManagerFactory method with vendor-specific instantiation code. This can be used to pass in a Spring-managed JDBC DataSource even with properties-driven PersistenceManagerFactory configuration, for example.

Most JDO implementations also provide a JCA connector, just like Hibernate does. As with Hibernate, it is usually not necessary to use the JCA connector for JTA integration; a locally defined PersistenceManagerFactory with a properly configured JTA transaction manager lookup is often sufficient. See "Setup as JCA Connector" earlier in this chapter for a discussion of the value of a JCA connector in the context of O/R mapping.

The DAO can now receive a reference to the JDO PersistenceManagerFactory instance via a Spring bean reference, just as a JDBC-based DAO receives a reference to a JDBC DataSource.

<bean       >   <property name="persistenceManagerFactory">     <ref bean="persistenceManagerFactory"/>   </property> </bean>

Whether the persistenceManagerFactory property, corresponding to the setPersistenceManagerFactory method, is defined by the provided JdoDaoSupport base class or implemented by the DAO class itself is not relevant here. The same configuration would work in both scenarios.

Transaction Management

While the JDO PersistenceManager API does provide its own means for transaction handling, this is typically not used in a Spring environment. Rather, transaction management is delegated to Spring's generic transaction facilities, with the generic TransactionTemplate or TransactionProxyFactoryBean used for demarcation (see Chapter 6 for details on Spring transaction management).

The following choices are available as backend transaction strategies for JDO:

  • org.springframework.orm.jdo.JdoTransactionManager: Allows transaction execution on a single JDO PersistenceManagerFactory, working on a single target database, using native JDO facilities. JDO-based DAOs can seamlessly participate in such transactions. This strategy is usually sufficient as long as there is no need for transactions that span multiple transactional resources.

  • org.springframework.transaction.jta.JtaTransactionManager: Delegates transaction execution to a JTA implementation, that is, to a J2EE server's JTA subsystem or a local JTA instance like ObjectWeb's JOTM. The JDO instance needs to be properly configured for JTA, which is vendor-specific. This strategy allows transactions to span and be coordinated across multiple transactional resources, for example multiple database systems.

In both cases, JDO PersistenceManagers will automatically be associated with transactions: one JDO PersistenceManager for the entire scope of a transaction. Data access code will automatically receive the transactional PersistenceManager if executing within a transaction; otherwise, a short-lived PersistenceManager will be opened for each operation. The only exception to this rule is when applying the Open PersistenceManager in View pattern (as described in the upcoming "Open PersistenceManager in View" section).

In case of suspended transactions, each transaction will be associated with its own JDO PersistenceManager. So when a new inner transaction is starting, the JDO PersistenceManager of the outer transaction will be suspended and a new one will be created. On completion of the inner transaction, the inner JDO PersistenceManager will be closed and the outer one will be resumed. This will work with both JdoTransactionManager and JtaTransactionManager, leveraging Spring's transaction synchronization mechanism.

Note that there is no support for direct JTA synchronization in Spring's JDO infrastructure. To benefit from transaction-scoped PersistenceManagers, you need to use Spring-driven transactions; plain JTA transactions or EJB-driven transactions are not sufficient, in contrast to Spring's Hibernate synchronization.

Important 

If there is a need to perform transactions across multiple resources, choose JtaTransactionManager, which delegates to the J2EE server's JTA subsystem (or a local JTA instance such as JOTM). However, for transactions on a single target database, JdoTransactionManager is perfectly sufficient — and will work in any environment, be it a J2EE web application, a standalone application, or a test suite.

PersistenceManager Lifecycle

As discussed, Spring always associates PersistenceManagers with transactions. Each transaction will use its own JDO PersistenceManager. More specifically, each transaction will use one transactional JDO PersistenceManager per PersistenceManagerFactory: that is, one per target database. So in the case of a JTA transaction, multiple PersistenceManagers might be involved in a single transaction — one per PersistenceManagerFactory.

Like a Hibernate Session, a JDO PersistenceManager effectively serves as transactional cache for persistent objects. It manages all loaded objects, to be able to wire them correctly in case of bidirectional associations, and to get notified of changes to persistent fields. On flush, SQL statements will be issued to synchronize the in-memory state with the database state. In JDO 2.0, a flush can also be triggered explicitly, to make other data access code see the changes within the same transaction.

One JDO PersistenceManager per transaction is usually a good fit. The PersistenceManager will represent all objects loaded within the transaction, in a consistent fashion. At transaction completion, all changes will be flushed and committed in a single database transaction. In the case of a transaction rollback, the JDO PersistenceManager will still be consistent, because it will have rolled back the state of the in-memory objects too; this is different from Hibernate, where a rollback does not reset the state of persistent objects.

At the time of this writing, the semantics of detaching and reattaching have not been fully clarified yet, as the JDO 2.0 specification is still in the draft phase. The current semantics of the reattach operation are different to Hibernate's saveOrUpdate operation in some respects, though. Most importantly, reattach cannot be used for persisting new instances; makePersistent needs to be used for that. Furthermore, reattach will fail if the instance is already associated with the current PersistenceManager; DAO operations need explicit checks for that case. The reattach operation is strictly meant for reattachment of existing instances that have been detached before, in contrast to Hibernate's more lenient saveOrUpdate.

Important 

While JDO 2.0's reattach operation appears superficially similar to Hibernate's saveOrUpdate, it behaves quite differently in the details. JDO-based DAOs need to be written more carefully to support all possible scenarios.

For special use cases, Spring provides org.springframework.orm.jdo.JdoInterceptor, analogous to HibernateInterceptor as discussed in the "Hibernate" section of this chapter. Usage of the JdoInterceptor allows the lifecycle of a JDO PersistenceManager to be tied to the scope of a method invocation on an AOP proxy. This can, for example, be used to enforce opening of a PersistenceManager at the beginning of a JTA transaction, instead of relying on automatic registration of a transactional PersistenceManager on first access. See the discussion of HibernateInterceptor for a configuration example; setting up and using a JdoInterceptor is analogous.

Open PersistenceManager in View

As with Hibernate, Spring supports the Open PersistenceManager in View pattern for JDO. Transactions end in the service layer, but the associated JDO PersistenceManager remains open until view rendering has been completed. This releases database locks early but still allows for lazy loading in the view. Spring supports this pattern out of the box, via org.springframework.orm.jdo.support.OpenPersistenceManagerInViewFilter (for use with any web tier) or OpenPersistenceManagerInViewInterceptor (for use with Spring's web MVC framework).

In principle, the usage patterns of OpenPersistenceManagerInViewFilter are similar to OpenSessionInViewFilter for Hibernate. JDO has the advantage that a PersistenceManager and the objects that it loaded do not become inconsistent in case of a transaction rollback, which effectively removes part of the need for a "deferred close" mode — if lazy loading is required, a single PersistenceManager per request is usually appropriate.

However, a single PersistenceManager being open for an entire request and being used for multiple transactions does incur side effects on detachment and reattachment, in particular on auto-detach-on-close, which unfortunately affect typical usage patterns in web MVC:

  • With transaction-scoped PersistenceManagers, auto-detachment would happen on transaction completion. So one could load an object first, modify it outside a transaction (for example populating it with HTTP request parameters), and reattach it to a new transaction.

  • With a single PersistenceManager for the entire request, auto-detachment will not happen during the request, so the object stays managed by the PersistenceManager — not allowing modifications outside a transaction. Even if the reattach operation accepted already attached objects too, all changes made in the meantime would get lost. This breaks such typical usage models in web MVC.

The only solutions for such a scenario are to either avoid a single PersistenceManager per request in the first place — loading all required data within transactions rather than relying on lazy loading — or to explicitly detach all objects to be modified outside a transaction (rather than rely on auto-detach-on-close). JDO's strict requirement for modifications to happen within a transaction restricts convenient usage models here.

Note 

Deferred close would cause even more severe issues with managed persistent objects. Every persistent instance needs to be registered with at most one PersistenceManager at any time. In Hibernate, this affects only managed collections; in JDO, all persistent instances are affected. As each PersistenceManager remains open when using deferred close, no auto-detachment would happen, which effectively does not allow any persistent object to be reattached to another transaction — unless having been explicitly detached before.

Important 

The Open PersistenceManager in View pattern involves different tradeoffs in JDO than the corresponding Open Session in View pattern does in Hibernate. On the one hand, JDO avoids inconsistencies in loaded state; on the other hand, it does not allow modifications outside transactions, which effectively breaks typical usage models in web MVC. The exact tradeoffs depend on the final semantics of the JDO2.0 specification, or on any vendor-specific auto-detachment features you might choose to use.

Configuration Examples

OpenPersistenceManagerInViewFilter needs to be set up in web.xml as a standard Servlet 2.3 Filter. The following configuration will apply it to all requests with a URL path that ends with .do:

<filter>   <filter-name>OpenPersistenceManagerInView</filter-name>   <filter-class>     org.springframework.orm.jdo.support.OpenPersistenceManagerInViewFilter   </filter-class> </filter>     <filter-mapping>   <filter-name>OpenPersistenceManagerInView</filter-name>   <url-pattern>*.do</url-pattern> </filter-mapping> 

The filter needs to be able to access the JDO PersistenceManagerFactory by default as a bean in the Spring root web application context (where middle tier resources usually reside). The default bean name is persistenceManagerFactory; this can be customized through a persistenceManagerFactoryBeanName init-param in web.xml.

<bean  class=     "org.springframework.orm.jdo.support.OpenPersistenceManagerInViewInterceptor">   <property name="persistenceManagerFactory">     <ref bean="persistenceManagerFactory"/>   </property> </bean>     <bean      >   <property name="interceptors">     <list>       <ref bean="openPersistenceManagerInView"/>     </list>   </property>   <property name="urlMap">     <map>       <entry key="/myUrlPath"><ref bean="myController"/></entry>     </map>   </property> </bean>

The PersistenceManagerFactory is passed in as a bean reference here because a HandlerInterceptor can be configured as bean. As the DispatcherServlet context is usually a child of the root web application context, a PersistenceManagerFactory bean defined there is visible and can be referenced directly.

JDO Dialect

JdoTransactionManager and JdoTemplate support certain advanced features that are not covered by the JDO 1.0 specification, namely:

  • Applying a transaction isolation level and/or a transaction timeout — as specified by a Spring transaction definition — to a native JDO transaction.

  • Access to the underlying JDBC Connection of a PersistenceManager, to let JDBC access code participate in JDO-managed transactions (working on the same JDBC Connection).

  • Eager flushing of a JDO transaction, to make changes visible to JDBC access code within the same transaction (through issuing corresponding SQL statements).

  • Sophisticated exception translation, from JDOException to Spring's DataAccessException hierarchy. Standard JDO exceptions allow only for limited sophistication in that respect.

Spring handles those features via the org.springframework.orm.jdo.JdoDialect SPI, an interface to be implemented for specific JDO vendors, supporting one or more of those features via vendor-specific API. The default implementation, org.springframework.orm.jdo.DefaultJdoDialect, simply throws appropriate exceptions when extended functionality is requested. Vendor-specific JdoDialects can be derived from that base class, using it as a convenient adapter for the JdoDialect interface.

DefaultJdoDialect implements exception translation through some standard JDOException checks, plus a detection of nested SQLExceptions, which will get translated through a Spring SQLExceptionTranslator (just like in the case of Spring JDBC and Spring's Hibernate support). Vendor-specific subclasses might refine translation according to special rules, or detect nested SQLExceptions in special ways.

An example for a vendor-specific JdoDialect is the JPOXJdoDialect class included in JPOX, a popular open source JDO implementation, which supports all of the previously mentioned advanced features. Other JDO vendors are expected to follow with a corresponding JdoDialect implementation for their respective tool.

Once the JDO 2.0 API becomes available, Spring's DefaultJdoDialect will be adapted to support the new standard JDO 2.0 ways of accessing the underlying JDBC Connection and flushing a JDO transaction. However, a vendor-specific subclass will still be necessary for transaction isolation levels and transaction timeouts, and might add value through more sophisticated exception translation. And of course, a specific JdoDialect implementation can still be used to adapt a JDO 1.0–compliant tool accordingly.

Several JDO vendors, including SolarMetric (vendors of the popular Kodo implementation) emphasize Spring integration and ship a JdoDialect integration for their product.

Important 

Spring's JDO support offers advanced features beyond the JDO 1.0 specification, most importantly special transaction semantics, access to the underlying JDBC Connection, and eager flushing. Spring's JdoDialect SPI can be implemented to provide support for those features, using a vendor-specific API. JDO 2.0 will standardize some — but not all — of those features, so the need for a vendor-specific JdoDialect should decline.

JDO: Summary

The JDO specification addresses the same level of O/R mapping as Hibernate: object-level querying and transparent persistence through automatic change detection. It uses a different query API style than Hibernate, namely JDOQL's programmatic query objects with sub-expressions, rather than Hibernate's textual HQL. Change detection happens through byte code modification, to receive notifications for each changed field in a managed persistent object, rather than through Hibernate-style snapshot comparisons.

While JDO 1.0 is a reasonably complete standard for general object persistence, it lacks specific support for relational databases and, even more importantly, support for detached objects (including proper reattachment). JDO 2.0 will remedy these deficiencies as far as possible; however, JDO's strict lifecycle requirements still make working with persistent objects harder than with Hibernate's lenient lifecycle handling. This is particularly prominent in typical web MVC usage models, where changes to persistent objects often happen outside transactions.

Of course, some JDO vendors already support a wide variety of extensions and JDO 2.0 preview features. If you require such features now — for example, detachment and reattachment — use appropriate, vendor- specific API behind your DAO facades. Migrating to the standard JDO 2.0 API will be straightforward.

The main JDO support facilities that Spring offers are:

  • org.springframework.orm.jdo.JdoTemplate: A data access class to be used in DAOs, seamlessly handling JDO PersistenceManagers in the background. It automatically participates in Spring-driven transactions and converts JDOExceptions into Spring's generic DataAccessException hierarchy.

  • org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean: A convenient way to set up a JDO PersistenceManagerFactory in a Spring context. PersistenceManagerFactory references can then be passed to DAOs, typically via Spring bean references. Alternatively, set up an instance of your vendor's PersistenceManagerFactory implementation class directly.

  • org.springframework.orm.jdo.JdoTransactionManager: A local transaction strategy, executing transactions on a single target PersistenceManagerFactory. This strategy works in any environment, in contrast to JtaTransactionManager, which depends on a J2EE server (or a standalone JTA implementation).

  • org.springframework.orm.jdo.support.JdoDaoSupport: A convenient base class for DAO implementations, taking a PersistenceManagerFactory reference and providing a JdoTemplate instance for it.

  • org.springframework.orm.hibernate.jdo.OpenPersistenceManagerInViewFilter and org.springframework.orm.hibernate.jdo.OpenPersistenceManagerInViewIntercept or: A Servlet 2.3 Filter and HandlerInterceptor for Spring's web MVC framework, respectively, providing the Open PersistenceManager in View pattern for JDO.

Mixing JDO access code with other data access strategies is possible, as long as all of them access the same JDBC DataSource. Spring's JdoTransactionManager can expose its transactions to JDBC-based access code, provided that there is an appropriate JdoDialect implementation. In such a scenario, adding Spring JDBC or iBATIS SQL Maps to the mix is reasonably easy: for example, for BLOB/CLOB or stored procedure access, or for read-only reference data.

Important 

Modern JDO implementations such as Kodo JDO or JPOX are powerful tools for full-fledged O/R mapping. The build-time enhancement step that most JDO implementations require is usually less burden than often perceived. However, the lack of support for detached objects in JDO 1.0 is a major issue, which will get addressed in JDO 2.0; many JDO implementations already support detachment and reattachment in a vendor-specific fashion.

JDO's main disadvantage is its strict lifecycle for persistent objects, which incurs a certain level of complexity that application developers have to deal with. In a typical web application, Hibernate is significantly more convenient to use, even given JDO extensions for detached objects. As with Hibernate, Spring JDBC and iBATIS SQL Maps are usually better options for legacy data models or over-normalized data models, in particular for read-only access.



Professional Java Development with the Spring Framework
Professional Java Development with the Spring Framework
ISBN: 0764574833
EAN: 2147483647
Year: 2003
Pages: 188

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