Java Data Objects by David Jordan and Craig Russell succeeds in giving a good introduction to JDO and providing a very good overview of the standard. The book covers all the relevant aspects of managing persistent Java objects, such as creating and deleting persistent objects, identity, queries, and transaction handling.
More importantly, the authors describe how to use JDO in practice, meaning how to use JDO to write a Java application that accesses persistent data transparently. There are lots of detailed, but easy to understand code examples explaining the concepts of JDO. I like the idea that the entire book uses a single application scenario. The source code is included in the appendix.
The descriptions do not depend on a particular JDO implementation. Instead, it focuses on how to write an application in a manner that is portable among different JDO implementations. Where necessary, it explains JDO's optional features and areas where JDO implementations may differ. JDO does not specify a standard for the mapping of persistent classes to specific datastores; but this is an important aspect of developing an application with JDO. There is a chapter about datastore mappings, with the focus on relational databases.
There are chapters about defining persistent classes, enhancing them, and setting up the JDO runtime environment. It is easy to transfer the provided examples to your own application environment. I like the chapter on JDOQL; it provides a good and in-depth description of the JDO query language. There are extra chapters about the identity and lifecycle of persistent instances, as well as nontransactional access of persistent data. The last two chapters describe how JDO integrates into web- and application-server environment, especially J2EE application servers.