UNDER CONSTRUCTION: Please provide feedback on this draft document' --Doug 13:02, 26 November 2007 (EST)
Best Practices for the use of EclipseLink JPA involves understanding all aspects of object-relational persistence. This can generally be broken down into mapping, querying (reading), transactions (writing) and Tuning.
- 1 Mapping
- 2 Querying
- 3 Transactions
- 4 Tuning
Mapping your domain model's entities to a relational database varies greatly from project to project and depending on the application's requirements and how the relational schema aligns with the domain model.
When developing your JPA mappings you can leverage the Eclipse Dali developer tooling to generate models from the database or generate the schema from the models. These are great tools to bootstrap development quickly. Dali also provides design time validation, annotation value code completion and a rich UI for mapping the complexities of a JPA model including the many defaults.
EclipseLink supports the use of JPA's @Version optimistic locking where a numeric or timestamp column tracks the version. For relational schemas where a version column cannot be added there are policies that allow existing columns to be used to ensure optimistic locking semantics.
See "Introduction to EclipseLink Application Development" in the EclipseLink User's Guide for more information.
M1. Map all Foreign Keys
M2. Use optimistic locking
It is important to take concurrency protection into consideration early in the development process. If there are entities that can be concurrently modified then some form of optimistic locking is a must to prevent database corruption.
M3. Configure the Cache
EclipseLink's default caching for each entity is to store it in the shared cache using a SOFT-WEAK cache of size 100. This means the last 100 accessed objects will be held in soft references and the remaining objects will be in weak references until the garbage collector removes them. This default caching is important to understand as it is aggressive in assuming that the data store does not change outside of the knowledge of this application instance. If your application will be running in a clustered deployment or other components in your system will be modifying the data store directly then it is important to configure your caching appropriately. EclipseLink offers support for customization of the default caching as well as per entity type.
The caching can basically be broken down into three types of usage:
- Reference (static/read-only) types
- Configure these using a FULL cache
- Configure the size to be at least as large as the maximum expected rows in the underlying table
- Read-mostly types
- Configure these using
- Volatile types
M4. Lazy Loading
The use of indirection (lazy-loading) enables EclipseLink to retrieve entities or portions of entities and then retrieve related entities or additional fields when accessed. Using indirection in your domain model not only offers obvious performance gains but also can minimize contention required when loading or refreshing an object. As a general guideline it is recommended to use indirection on all relationships.
Note: When you use indirection there are additional constraints introduced dealing with serialization of the domain model. In order to have indirect relationships instantiated across a remote call they must be instantiated before being serialized.
M5. Don't Map 1:Million
Many applications read more data then they write. It is important to optimize reads leveraging the EclipseLink cache
Q1. Only load entities when needed
All queries generally return the full entity which can then be reused and can easily be included in a transaction without re-loading. There is a cost associated with reading all columns of an entity and constructing it within the cache. This cost is acceptable if the full entity is required or the entity will likely be involved in a transaction. If neither of these conditions are met you may want to consider minimizing your entity loading costs using:
Q2. Optimize graph/aggregate loading
EclipseLink enables the optimization of graph loading using both JPQL's FETCH JOIN as well as query hint extensions that enable join and batch loading of related objects in order to minimize the number of SQL statements required.
T1. Handle Optimistic Lock Failures
T2. Leverage JDBC
While it is important to consider performance and scalability tuning in all aspects (mapping, querying, and transactions) it is also valuable to tune the overall application and address performance issues identified in the persistence layer.