Java Persistence Practice Guide
Java Persistence Practice Guide
Contents
1. Preface
2. What is Java persistence?
1. What is Java?
2. What is a database?
3. What is JPA?
4. What is new in JPA 2.0?
5. Other Persistence Specs
6. Why use JPA or ORM?
3. Persistence Products, Which to Use?
1. EclipseLink (Eclipse)
2. TopLink (Oracle)
3. Hibernate (RedHat)
4. TopLink Essentials (Glassfish)
5. Kodo (Oracle)
6. Open JPA (Apache)
7. Ebean (SourceForge)
4. Mapping, Round Pegs into Square Holes
1. Tables
2. Identity, Primary Keys and Sequencing
3. Inheritance
4. Embeddables (Aggregates, Composite or Component Objects)
5. Locking and Concurrency
6. Basic Attributes
7. Relationships
1. OneToOne
2. ManyToOne
3. OneToMany
4. ManyToMany
Java Persistence/ Print version 2
5. Embedded
8. Advanced Mappings
1. ElementCollection (Embeddable Collections, Basic Collections)
2. Variable Relationships
9. Advanced Topics
1. Views
2. #Stored Procedures/
3. #Structured Object-Relational Data Types/
4. #XML Data Types/
5. #Filters/
6. #History/
7. #Logical Deletes/
8. #Auditing/
9. #Replication/
5. Runtime, Doing the Hokey Pokey (EntityManager)
1. Querying
1. JPQL
2. Persisting (Inserting, Updating, Merging)
3. Transactions
4. Caching
5. EJB
6. Security (User Authentication, Proxy Connections, VPD)
7. #Servlets and JSPs/
8. #Spring/
9. #WebServices/
6. #Packaging and Deploying/
1. #Java EE/
1. Oracle Weblogic
2. IBM Websphere
3. Redhat JBoss
2. #Spring/
3. #Tomcat/
7. #Clustering/
8. Databases
1. Oracle
2. PostgreSQL
3. MySQL
4. DB2
5. SQL Server
9. Debugging
10. Performance
11. Tools
1. Eclipse JPA (Dali)
2. TopLink Mapping Workbench
12. Testing
Java Persistence/ Print version 3
Preface
Intended Audience
This book is intended to be useful for or to anyone learning to, or developing Java
applications that require persisting data to a database. It is mainly intended for
Java developers intending to persist Java objects through the Java Persistence API (JPA)
standard to a relational database. Please don't just read this book, if you're learning or
developing with JPA please contribute your experiences to this book.
Style
This book is meant to be written in a casual manner. The goal is avoid sounding
dry, overly technical, or impersonal. The book should sound casual, like a
co-worker explaining to you how to use something, or a fellow consultant relating their
latest engagement to another. Please refrain for being overly critical of any product,
ranting about bugs, or marketing your own product or services.
Authors
Everyone is encouraged to participate in the ongoing development of this book.
You do not need to be a Java persistence superstar to contribute, many times the
best advice/information for other users comes from first time users who have not yet been
conditioned to think something that may be confusing is obvious.
List of authors: (please contribute and sign your name)
James Sutherland : Currently working on Oracle TopLink and Eclipse EclipseLink, over 12
years of experience in object persistence and ORM.
Doug Clarke : Oracle TopLink and Eclipse EclipseLink, over 10 years of experience in the
object persistence industry.
Java Persistence/ Print version 4
What is Java?
Java is an object oriented programming language first released by Sun Microsystems in
1995. It blended concepts from existing languages such as C++ and Smalltalk into a new
programming language. It achieved its success over the many rival languages of the day
because it was associated with this newish thing called the "Internet" in allowing Java
applets to be embedded in web pages and run using Netscape. Its other main reason for
success was unlike many of its competitors it was open, "free", and not embedded with a
integrated development environment (IDE). Java also included the source code to its class
library. This enabled Java to be adopted by many different companies producing their own
Java development environments but sharing the same language, this open model fostered
the growth in the Java language and continues today with the open sourcing of Java.
Java quickly moved from allowing developers to build dinky applets to being the standard
server-side language running much of the Internet today. The Enterprise Edition (JEE) of
Java was defined to provide an open model for server application to be written and portable
across any compliant JEE platform provider. The JEE standard is basically a basket of other
Java specifications brought together under one umbrella and has major providers including
IBM WebSphere, RedHat JBoss, Sun Glassfish, BEA WebLogic, Oracle AS and many others.
Java Persistence/ Print version 5
Google Trends
[1][2]
• Programming Languages
• JEE Servers [3][4]
[1] http:/ / www. google. com/ trends?q=c%23%2C+ php%2C+ java%2C+ c%2B%2B%2C+ perl& ctab=0&
geo=all& date=all& sort=0
[2] Unfortunately hard to seperate Java island from Java language.
[3] http:/ / www. google. com/ trends?q=websphere%2C+ weblogic%2C+ jboss%2C+ glassfish%2C+ geronimo+
apache& ctab=0& geo=all& date=all& sort=0
[4] Could not include Oracle because of Oracle database hits.
See also
• Java Programming
What is a database?
A database is a program that stores data. There are many types of databases, flat-file,
hierarchical, relational, object-relational, object-oriented, xml, and others. The original
databases were mainly proprietary and non-standardized.
Relational database were the first databases to achieve great success and standardization,
relational database are characterize by the SQL (structured query language) standard to
query and modify the database, their client/server architecture, and relational table storage
structure. Relational databases achieve great success because their standardization
allowed many different vendors such as Oracle, IBM, and Sybase to produce interoperable
products giving users the flexibility to switch their vendor and avoid vendor lock-in to a
proprietary solution. Their client/server architecture allows the client programming
language to be decoupled from the server, allowing the database server to support
interface APIs into multiple different programming languages and clients.
Although relational database are relatively old technology they still dominate the industry.
There have been many attempts to replace the relational model, first with object-oriented
databases, then with object-relational databases, and finally with xml database, but none of
the new database models achieved much success and relational database remain the
overwhelming dominate database model.
The main relational databases used today are, Oracle, MySQL (Sun), PostgreSQL, DB2
(IBM), SQL Server (Microsoft).
• Google trend for databases (http:/ / www. google. com/ trends?q=oracle,+ sybase,+ sql+
server,+ mysql,+ db2& ctab=0& geo=all& date=all& sort=0)
What is JPA?
The Java Persistence Architecture API (JPA) is a Java specification for accessing, persisting
and managing data between Java objects / classes and the relational database. JPA was
defined as part of the EJB 3.0 specification as a replacement to the EJB 2 CMP Entity Beans
specification. It is now considered the standard industry approach for Object to Relational
Mapping (ORM) in the Java Industry.
JPA is just a specification, it is not a product, and cannot perform persistence, or anything
by itself. JPA is just a set of interfaces, and requires an implementation. There are open
Java Persistence/ Print version 6
source and commercial JPA implementations to choose from and any Java EE 5 application
server should provide support for its use. JPA also requires a database to persist to.
JPA allows POJO (Plain Old Java Objects) to be easily persisted without requiring the classes
to implement any interfaces or methods as the EJB 2 CMP specification required. JPA
allows an object's object-relational mappings to be defined through standard annotations or
XML defining how the Java class maps to a relational database table. JPA also defines a
runtime EntityManager API for processing queries and transaction on the objects against
the database. JPA defines an object-level query language JPQL to allow querying of the
objects from the database.
JPA is the latest of several Java persistence specifications. The first was the OMG
persistence service Java binding, which was never very successful and I'm not sure of any
commercial products supporting it. Next came EJB 1.0 CMP Entity Beans, which was very
successful in being adopted by the big Java EE providers (BEA, IBM), but there was a
backlash against the spec by some users who thought the spec requirements on the Entity
Beans overly complex and overhead and performance poor. EJB 2.0 CMP tried to reduce
some of the complexity of Entity Beans through introducing local interfaces, but the
majority of the complexity remained. EJB 2.0 also lacked portability, in that the deployment
descriptors defining the object-relational mapping were not specified and all proprietary.
This backlash in part led to the creation of another Java persistence specification JDO (Java
Data Objects). JDO obtained somewhat of a "cult" following of several independent vendors
such as Kodo JDO, and several open source implementation, but never had much success
with the big Java EE vendors.
Despite the two competing Java persistence standards of EJB CMP and JDO, the majority of
users continued to prefer proprietary api solutions, mainly TopLink (which had been around
for some time and had its own POJO API) and Hibernate (which was a relatively new open
source product that also had its own POJO API and was quickly becoming the open source
industry standard). The TopLink product formerly owned by WebGain was also acquired by
Oracle, increasing it's influence on the Java EE community.
The EJB CMP backlash was only part of a backlash against all of Java EE which was seen as
too complex in general and prompted such products as the Spring container. This led the
EJB 3.0 specification to have a main goal of reducing the complexity, which lead the spec
committee down the path of JPA. JPA was meant to unify the EJB 2 CMP, JDO, Hibernate,
and TopLink API's and products, and seems to have been very successful in doing so.
Currently most of the persistence vendors have released implementations of JPA confirming
its' adoption by the industry and users. These include Hibernate (acquired by JBoss,
acquired by Red Hat), TopLink (acquired by Oracle), and Kodo JDO (acquired by BEA,
acquired by Oracle). Other products that have added support for JPA include Cocobase
(owned by Thought Inc.), and JPOX.
• EJB JPA Spec (http:/ / jcp. org/ aboutJava/ communityprocess/ final/ jsr220/ index. html)
• JPA ORM XML Schema (http:/ / java. sun. com/ xml/ ns/ persistence/ orm_1_0. xsd)
• JPA Persistence XML Schema (http:/ / java. sun. com/ xml/ ns/ persistence/
persistence_1_0. xsd)
• JPA JavaDoc (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/
package-summary. html)
• JPQL BNF
Java Persistence/ Print version 7
Resources
• JPA 2.0 Spec (http:/ / jcp. org/ en/ jsr/ detail?id=317)
• Eclipse EclipseLink to be JPA 2.0 Reference Implementation (http:/ / www. eclipse. org/
org/ press-release/ 20080317_Eclipselink. php)
• JPA 2.0 Reference Implementation Development (on EclipseLink) (http:/ / wiki. eclipse.
org/ EclipseLink/ Development/ JPA)
EJB CMP (Enterprise Java Beans, Container Managed 2.1 (EJB) 2003
Persistence)
Persistence Products
There are many persistence products to choose from. Most persistence products now
support a JPA interface, although there still are some exceptions. Which product you use
depends on your preference, but most people would recommend you use the JPA standard
whichever product you choose. This gives you the flexibility to switch persistence providers,
or port your application to another server platform which may use a different persistence
Java Persistence/ Print version 9
provider.
Determining which persistence product to use involves many criteria. Valid things to
consider include:
• Which persistence product does your server platform support and integrate with?
• What is the cost of the product, is it free and open source, can you purchase enterprise
level support and services?
• Do you have an existing relationship with the company producing the product?
• Is the product active and does it have a large user base?
• How does the product perform and scale?
• Does the product integrate with your database platform?
• Does the product have active and open forums, do questions receive useful responses?
• Is the product JPA compliant, what functionality does the product offer beyond the JPA
specification?
Hibernate Yes 3.3.1 2008 Yes JBoss 650 (http:/ / forum. hibernate. org/
(Red Hat) viewforum. php?f=1)
EclipseLink Yes 1.0.2 2008 Yes OracleAS 81 (http:/ / www. nabble. com/
(Eclipse) (11g), EclipseLink---Users-f26658. html)
Oracle
Weblogic
(10.3),
Glassfish
(v3)
TopLink Yes Yes 11g 2008 OracleAS 80 (http:/ / forums. oracle. com/
(Oracle) (11g), forums/ forum. jspa?forumID=48)
Oracle
Weblogic
(10.3)
OpenJPA Yes 1.0.3 2008 Yes Geronimo 60 (http:/ / www. nabble. com/
(Apache) OpenJPA-Users-f23252. html)
JPOX (http:/ / Yes Yes 1.2.3 2008 Yes 21 (http:/ / www. jpox. org/ servlet/
www. jpox. forum/ index)
org/ )
(SourceForge)
TopLink Yes 2.0 2007 Yes Glassfish 13 (http:/ / www. nabble. com/
Essentials (v2), SunAS java.
(java.net) (9), net---glassfish-persistence-f13455.
OracleAS html)
(10.1.3)
Kodo (Oracle) Yes Yes 4.1 2007 Oracle 0 (http:/ / forums. bea. com/ bea/
WebLogic forum. jspa?forumID=500000029)
(10.3)
[2] Application server that includes the product as their JPA implementation
[3] Number of user forum posts for 2008-10. Note this is only an estimate of community size and may be
misleading due to several factors including users of open source products are more likely to post to forums,
where as users of commercial products are more likely to use support. The estimate is also confused by the fact
that some users post questions to generic EJB, JPA or ORM forums.
EclipseLink
EclipseLink is the open source Eclipse Persistence Services Project from the Eclipse
Foundation. The product provides an extensible framework that allows Java developers to
interact with various data services, including databases, XML, and Enterprise Information
Systems (EIS). EclipseLink supports a number of persistence standards including the Java
Persistence API (JPA), Java API for XML Binding (JAXB), Java Connector Architecture (JCA),
and Service Data Objects (SDO).
EclipseLink is based on the TopLink product, which Oracle contributed the source code
from to create the EclipseLink project. The original contribution was from TopLink's 11g
code base, and the entire code-base/feature set was contributed, with only EJB 2 CMP and
some minor Oracle AS specific integration removed. This differs from the TopLink
Essentials Glassfish contribution, which did not include some key enterprise features. The
package names were changed and some of the code was moved around.
The TopLink Mapping Workbench UI has also been contributed to the project.
EclipseLink is the intended path forward for persistence for Oracle and TopLink. It is
intended that the next major release of Oracle TopLink will include EclipseLink as well as
the next major release of Oracle AS.
EclipseLink supports usage in an OSGi environment.
EclipseLink was announced to be the JPA 2.0 reference implementation, and announced to
be the JPA provider for Glassfish v3.
• EclipseLink Home (http:/ / www. eclipse. org/ eclipselink/ )
• EclipseLink Newsgroup (http:/ / www. eclipse. org/ newsportal/ thread.
php?group=eclipse. technology. eclipselink)
• EclipseLink Wiki (http:/ / wiki. eclipse. org/ EclipseLink)
TopLink
TopLink is one of the leading Java persistence products and JPA implementations. TopLink
is produced by Oracle and part of Oracle's OracleAS, WebLogic, and OC4J servers.
As of TopLink 11g, TopLink bundles the open source project EclipseLink for most of its
functionality.
The TopLink 11g release supports the JPA 1.0 specification. TopLink 10.1.3 also supports
EJB CMP and is the persistence provider for OracleAS OC4J 10.1.3 for both JPA and EJB
CMP. TopLink provides advanced object-relational mapping functionality beyond the JPA
specification, as well as providing persistence for object-relational data-types, and
Enterprise Information Systems (EIS/mainframes). TopLink includes sophisticated object
caching and performance features. TopLink provides a Grid extension that integrate with
Oracle Coherence. TopLink provides object-XML mapping support and provides a JAXB
implementation and web service integration. TopLink provides a Service Data Object (SDO)
implementation.
Java Persistence/ Print version 11
TopLink provides a rich user interface through the TopLink Mapping Workbench. The
Mapping Workbench allows for graphical mapping of an object model to a data model, as
allows for generation of a data model from an object model, and generation of an object
model from a data model, and auto-mapping of an existing object and data model. The
TopLink Mapping Workbench functionality is also integrated with Oracle's JDeveloper IDE.
TopLink contributed part of its source code to become the JPA 1.0 reference
implementation under the Sun java.net Glassfish project. This open-source product is called
TopLink Essentials, and despite a different package name (oracle.toplink.essentials) it is
basically a branch of the source code of the TopLink product with some advanced
functionality stripped out.
TopLink contributed practically its entire source code to the Eclipse Foundation EclipseLink
product. This is an open source product currently in incubation that represents the path
forward for TopLink. The package name is different (org.eclipse.persistence) but the source
code it basically a branch of the TopLink 11g release. Oracle also contributed its Mapping
Workbench source code to the project. The TopLink Mapping Workbench developers also
were major contributors to the Eclipse Dali project for JPA support.
TopLink was first developed in Smalltalk and ported to Java in the 90's, and has over 15
years worth of object persistence solutions. TopLink originally provided a proprietary POJO
persistence API, when EJB was first released TopLink provided one of the most popular EJB
CMP implementations, although it continued to recommend its POJO solution. TopLink also
provided a JDO 1.0 implementation for a few releases, but this was eventually deprecated
and removed once the JPA specification had been formed. Oracle and TopLink have been
involved in each of the EJB, JDO and EJB3/JPA expert groups, and Oracle was the co-lead
for the EJB3/JPA specification.
• Oracle TopLink Home (http:/ / www. oracle. com/ technology/ products/ ias/ toplink/
index. html)
• Oracle TopLink Forum (http:/ / forums. oracle. com/ forums/ forum. jspa?forumID=48)
• Oracle TopLink Wiki (http:/ / wiki. oracle. com/ page/ TopLink)
TopLink Resources
• TopLink Automatic Schema Generation Options (http:/ / docs. sun. com/ app/ docs/ doc/
819-3672/ gbwmk?a=view)
Hibernate
Hibernate was an open source project developed by a team of Java software developers
around the world led by Gavin King. JBoss, Inc. (now part of Red Hat) later hired the lead
Hibernate developers and worked with them in supporting Hibernate.
The current version of Hibernate is Version 3.x. Hibernate provides both a proprietary
POJO API, and JPA support.
Java Persistence/ Print version 12
TopLink Essentials
TopLink Essentials is an open source project from the Sun java.net Glassfish community. It
is the EJB3 JPA 1.0 reference implementation, and is the JPA provider for the Sun Glassfish
v1 application server.
TopLink Essentials was based on the TopLink product, which Oracle contributed some of
the source code from to create the TopLink Essentials project. The original contribution
was from TopLink's 10.1.3 code base, only some of the TopLink product source code was
contributed, which did not include some key enterprise features. The package names were
changed and some of the code was moved around.
TopLink Essentials has been somewhat replaced by the EclipseLink project. EclipseLink will
be the JPA 2.0 reference implementation and be part of Sun Glassfish v3.
• TopLink Essentials Home (https:/ / glassfish. dev. java. net/ javaee5/ persistence/ index.
html)
• TopLink Essentials Forum (http:/ / www. nabble. com/ java.
net---glassfish-persistence-f13455. html)
• TopLink Essentials Wiki (http:/ / wiki. glassfish. java. net/ Wiki.
jsp?page=TopLinkEssentials)
Kodo
Kodo (http:/ / www. bea. com/ kodo/ ), was originally developed as an Java Data Objects
(JDO) implementation, by SolarMetric. BEA Systems acquired SolarMetric in 2005, where
Kodo was expanded to be an implementation of both the JDO and JPA specifications. In
2006, BEA donated a large part of the Kodo source code to the Apache Software
Foundation under the name OpenJPA. BEA (and Kodo) were acquired by Oracle.
Open JPA
OpenJPA is an Apache project for supporting the JPA specification. Its' source code was
originally donated from (part of) BEA's Kodo product.
Ebean (http:/ / www. avaje. org) is a Java ORM based on the JPA specification.
The goal of Ebean is to provide mapping compatible with JPA while providing a simpler API
to use and learn.
• @EnumMapping
• @Formula
Mapping
The first thing that you need to do to persist something in Java is define how it is to be
persisted. This is called the mapping process ( details (http:/ / en. wikipedia. org/ wiki/
Object-Relational_impedance_mismatch)). There have been many different solutions to the
mapping process over the years, including some object-databases that didn't require you
map anything, just lets you persist anything directly. Object-relational mapping tools that
would generate an object model for a data model that included the mapping and
persistence logic in it. ORM products that provided mapping tools to allow the mapping of
Java Persistence/ Print version 13
an existing object model to an existing data model and stored this mapping meta-data in flat
files, database tables, XML and finally annotations.
In JPA mappings can either be stored through Java annotations, or in XML files. One
significant aspect of JPA is that only the minimal amount of mapping is required. JPA
implementations are required to provide defaults for almost all aspects of mapping and
object.
The minimum requirement to mapping an object in JPA is to define which objects can be
persisted. This is done through either marking the class with the @Entity (https:/ / java.
sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ Entity. html) annotation, or adding an
<entity> tag for the class in the persistence unit's ORM XML file. Also the primary key, or
unique identifier attribute(s) must be defined for the class. This is done through marking
one of the class' fields or properties (get method) with the @Id annotation, or adding an
<id> tag for the class' attribute in the ORM XML (http:/ / java. sun. com/ xml/ ns/
persistence/ orm_1_0. xsd) file.
The JPA implementation will default all other mapping information, including defaulting the
table name, column names for all defined fields or properties, cardinality and mapping of
relationships, all SQL and persistence logic for accessing the objects. Most JPA
implementations also provide the option of generating the database tables at runtime, so
very little work is required by the developer to rapidly develop a persistent JPA application.
Common Problems
My annotations are ignored
This typically occurs when you annotate both the fields and methods (properties) of
the class. You must choose either field or property access, and be consistent. Also
when annotating properties you must put the annotation on the get method, not the set
method. Also ensure that you have not defined the same mappings in XML, which may
be overriding the annotations. You may also have a classpath issue, such as having an
old version of the class on the classpath.
Odd behavior
There are many reasons that odd behavior can occur with persistence. One common
issue that can cause odd behavior is using property access and putting side effects in
your get or set methods. For this reason it is generally recommended to use field
access in mapping, i.e. putting your annotations on your variables not your get
methods.
For example consider:
This may look innocent, but these side effects can have unexpected consequences. For
example if the relationship was lazy this would have the effect of always instantiating
the collection when set from the database. It could also have consequences with
certain JPA implementations for persisting, merging and other operations, causing
duplicate inserts, missed updates, or a corrupt object model.
I have also seen simply incorrect property methods, such as a get method that always
returns a new object, or a copy, or set methods that don't actually set the value.
In general if you are going to use property access, ensure your property methods are
free of side effects. Perhaps even use different property methods than your application
uses.
Tables
A table is the basic persist structure of a relational database.
A table contains a list of columns which define the table's
structure, and a list of rows that define the table's data.
Each column has a specific type and generally size. The
standard set of relational types are limited to basic types
including numeric, character, date-time, and binary
(although most modern databases have additional types and
typing systems). Tables can also have constraints that define
the rules which restrict the row data, such as primary key,
foreign key, and unique constraints. Tables also have other
artifacts such as indexes, partitions and triggers.
A typical mapping of a persist class will map the class to a single table. In JPA this is
defined through the @Table (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ Table. html) annotation or <table> XML element. If no table annotation is
present, the JPA implementation will auto assign a table for the class, the JPA default table
name is the name of the class as uppercase (minus the package). Each attribute of the class
will be stored in a column in the table.
Java Persistence/ Print version 16
Advanced
Although in the ideal case each class would map to a single table, this is not always
possible. Other scenarios include:
• Multiple tables : One class maps to 2 or multiple tables.
• Sharing tables : 2 or multiple classes are stored in the same table.
• Inheritance : A class is involved in inheritance and has an inherited and local table.
• Views : A class maps to a view.
• Stored procedures : A class maps to a set of stored procedures.
• Partitioning : Some instances of a class map to one table, and other instances to another
table.
• Replication : A class's data is replicated to multiple tables.
• History : A class has historical data.
These are all advanced cases, some are handled by the JPA Spec and many are not. The
following sections investigate each of these scenarios further and include what is supported
by the JPA spec, what can be done to workaround the issue within the spec, and how to use
some JPA implementations extensions to handle the scenario.
Multiple tables
Sometimes a class maps to multiple tables. This
typically occurs on legacy or existing data models
where the object model and data model do not match. It
can also occur in inheritance when subclass data is
stored in additional tables. Multiple tables may also be
used for performance, partitioning or security reasons.
JPA allows multiple tables to be assigned to a single class. The @SecondaryTable (https:/ /
java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ SecondaryTable. html) and
SecondaryTables annotations or <secondary-table> elements can be used. By default the
@Id column(s) are assumed to be in both tables, such that the secondary table's @Id
column(s) are the primary key of the table and a foreign key to the first table. If the first
table's @Id column(s) are not named the same the @PrimaryKeyJoinColumn (https:/ / java.
sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ PrimaryKeyJoinColumn. html) or
Java Persistence/ Print version 17
@OneToOne
@JoinColumn(name="MGR_ID", table="EMP_DATA",
referencedColumnName="EMP_ID")
private Employee manager;
...
}
With the @PrimaryKeyJoinColumn the name refers to the foreign key column in the
secondary table and the referencedColumnName refers to the primary key column in the
first table. If you have multiple secondary tables, they must always refer to the first table.
When defining the table's schema typically you will define the join columns in the secondary
table as the primary key of the table, and a foreign key to the first table. Depending how
Java Persistence/ Print version 18
you have defined your foreign key constraints, the order of the tables can be important, the
order will typically match the order that the JPA implementation will insert into the tables,
so ensure the table order matches your constraint dependencies.
For relationships to a class that has multiple tables the foreign key (join column) always
maps to the primary table of the target. JPA does not allow having a foreign key map to a
table other than the target object's primary table. Normally this is not an issue as foreign
keys almost always map to the id/primary key of the primary table, but in some advanced
scenarios this may be an issue. Some JPA products allow the column or join column to use
the qualified name of the column (i.e.
@JoinColumn(referenceColumnName="EMP_DATA.EMP_NUM"), to allow this type of
relationship. Some JPA products may also support this through their own API, annotations
or XML.
One way to solve the issue is simply to swap your primary and secondary tables. This will
result in having the secondary table referencing the primary tables primary key and is
within the spec. This however will have side-effects, one being that you now changed the
primary key of your object from EMP_ID to ADDRESS_ID, and may have other mapping and
querying implications. If you have more than 2 tables this also may not work.
Another option is to just use the foreign key column in the @PrimaryKeyJoinColumn, this
will technically be backward, and perhaps not supported by the spec, but may work for
some JPA implementations. However this will result in the table insert order not matching
the foreign key constraints, so the constraints will need to be removed, or deferred.
It is also possible to map the scenario through a database view. A view could be defined
joining the two tables and the class could be mapped to the view instead of the tables.
Views are read-only on some databases, but many also allow writes, or allow triggers to be
used to handle writes.
Some JPA implementations provide extensions to handle this scenarios.
TopLink, EclipseLink : Provides a proprietary API for its mapping model
ClassDescriptor.addForeignKeyFieldNameForMultipleTable() that allows for
arbitrary complex foreign keys relationships to be defined among the secondary tables.
Java Persistence/ Print version 19
Again this scenario could be handled through redesigning the data or object model, or
through using a view. Some JPA implementations provide extensions to handle this
scenarios.
TopLink, EclipseLink : Provides a proprietary API for its mapping model
DescriptorQueryManager.setMultipleTableJoinExpression() that allows for
arbitrary complex multiple table joins to be defined. This can be configured through
using a @DescriptorCustomizer annotation and DescriptorCustomizer class.
@Table("\"Employee Data\"")
Some databases support mixed case table and column names, and others are case
insensitive. If your database is case insensitive, or you wish your data model to be portable,
it is best to use all uppercase names. This is normally not a big deal with JPA where you
rarely use the table and column names directly from your application, but can be an issue in
certain cases if using native SQL queries.
</entity-mappings>
Identity
An object id (OID) is something that uniquely identifies an object. Within a VM this is
typically the object's pointer. In a relational database table a row is uniquely identified in
its' table by its' primary key. When persisting objects to a database you need a unique
identifier for the objects, this allows you to query the object, define relationships to the
object, and update and delete the object. In JPA the object id is defined through the @Id
(https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ Id. html) annotation or
<id> element and should correspond to the primary key of the object's table.
Example id annotation
...
@Entity
public class Employee {
@Id
private long id
...
}
Example id XML
<entity name="Employee" class="org.acme.Employee" access="FIELD">
<id name="id"/>
<entity/>
Common Problems
No primary key.
See No Primary Key.
Sequencing
An object id can either be a natural id or a generated id. A natural id is one that occurs in
the object and has some meaning in the application. Examples of natural ids include user
ids, email addresses, phone numbers, and social insurance numbers. A generated id is one
that is generated by the system. A sequence number in JPA is a sequential id generated by
the JPA implementation and automatically assigned to new objects. The benefits of using
sequence numbers are that they are guaranteed to be unique, allow all other data of the
object to change, are efficient values for querying and indexes, and can be efficiently
assigned. The main issue with natural ids is that everything always changes at some point;
even a person's social insurance number can change. Natural ids can also make querying,
foreign keys and indexing less efficient in the database.
In JPA an @Id can be easily assigned a generated sequence number through the
@GeneratedValue (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/
GeneratedValue. html) annotation, or <generated-value> element.
Sequence Strategies
There are several strategies for generating unique ids. Some strategies are database
agnostic and others make use of built-in databases support.
JPA provides support for several strategies for id generation defined through the
GenerationType (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/
GenerationType. html) enum, TABLE, SEQUENCE and IDENTITY.
The choice of which sequence strategy to use is important as it effect performance,
concurrency and portability.
Table sequencing
Table sequencing uses a table in the database to generate unique ids. The table has two
columns, one stores the name of the sequence, the other stores the last id value that was
assigned. There is a row in the sequence table for each sequence object. Each time a new id
is required the row for that sequence is incremented and the new id value is passed back to
the application to be assigned to an object. This is just one example of a sequence table
schema, for other table sequencing schemas see Customizing.
Java Persistence/ Print version 23
Table sequencing is the most portable solution because it just uses a regular database
table, so unlike sequence and identity can be used on any database. Table sequencing also
provides good performance because it allows for sequence pre-allocation, which is
extremely important to insert performance, but can have potential concurrency issues.
In JPA the @TableGenerator (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ TableGenerator. html) annotation or
SEQ_NAMESEQ_COUNTEMP_SEQ123PROJ_SEQ550
Common Problems
initial row in the sequence table for your sequence with the initial id (i.e. INSERT INTO
SEQUENCE_TABLE (SEQ_NAME, SEQ_COUNT) VALUES ("EMP_SEQ", 0)), or let your JPA
provider create your schema for you.
Sequence objects
Sequence objects use special database objects to generate ids. Sequence objects are only
supported in some databases, such as Oracle and Postgres. In Oracle a SEQUENCE object
has a name, INCREMENT, and other database object settings. Each time the
<sequence>.NEXTVAL is selected the sequence is incremented by the INCREMENT.
Sequence objects provide the optimal sequencing option, as they are the most efficient and
have the best concurrency, however they are the least portable as most databases do not
support them. Sequence objects support sequence preallocation through setting the
INCREMENT on the database sequence object to the sequence preallocation size.
In JPA the @SequenceGenerator (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ SequenceGenerator. html) annotation or <sequence-generator> element is
used to define a sequence object. The SequenceGenerator defines a sequenceName for the
name of the database sequence object, and an allocationSize for the sequence
preallocation size or sequence object INCREMENT.
Common Problems
Identity sequencing
Identity sequencing uses special IDENTITY columns in the database to allow the database
to automatically assign an id to the object when its' row is inserted. Identity columns are
supported in many databases, such as MySQL, DB2, SQL Server, Sybase and Postgres.
Oracle does not support IDENTITY columns but they can be simulated through using
sequence objects and triggers.
Although identity sequencing seems like the easiest method to assign an id, they have
several issues. One is that since the id is not assigned by the database until the row is
inserted the id cannot be obtained in the object until after commit or after a flush call.
Identity sequencing also does not allow for sequence preallocation, so can require a select
for each object that is inserted, potentially causing a major performance problem, so in
general are not recommended.
In JPA there is no annotation or element for identity sequencing as there is no additional
information to specify. Only the GeneratedValue's strategy needs to be set to IDENTITY.
Common Problems
Advanced
sequence number, but sometimes a composite primary key is desirable and unavoidable.
Composite primary keys can be common in legacy database schemas, where cascaded keys
can sometimes be used. This is where you have a model where dependent objects include
their parent's primary key, i.e. COMPANY's primary key is COMPANY_ID, DEPARTMENT's primary
key is composed of COMPANY_ID, and DEP_ID, EMPLOYEE's primary key is composed of
COMPANY_ID, DEP_ID, and EMP_ID, and so on. Some OO Java designers may find this type of
model disgusting, but some DBA's actually think it is the correct model. Issues with the
model include the obvious fact that Employee's cannot switch departments, but also foreign
key relationships become more complex and all primary key queries, updates, deletes,
caching become less efficient. On the plus side, each department has control over their own
ids, and it you need to partition the database EMPLOYEE table, you can easily do so based on
the COMPANY_ID or DEP_ID, as these are included in every query.
Other common usages of composite primary key include many-to-many relationships where
the join table has additional columns, so the table is mapped to an object, whose primary
key consists of both foreign key columns. Also dependent or aggregate one-to-many
relationships where the child object's primary key consists of its' parent's primary key and a
locally unique field.
There are two methods of declaring a composite primary key in JPA, IdClass and
EmbeddedId.
Id Class
An IdClass defines a separate Java class to represent the primary key. It is defined
through the @IdClass (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/
IdClass. html) annotation or <id-class> XML element. The IdClass must define an
attribute (field/property) that mirrors each Id attribute in the entity. It must have the same
attribute name and type. When using an IdClass you still require to mark each Id
attribute in the entity with @Id.
The main purpose of the IdClass is to be used as the structure passed to the
EntityManager find() and getReference() API. Some JPA products also use the IdClass
Java Persistence/ Print version 28
as a cache key to track an object's identity. Because of this, it is required (depending on JPA
product) to implement an equals() and hashCode() method on the IdClass. Ensure that
the equals() method checks each part of the primary key, and correctly uses equals for
objects and == for primitives. Ensure that the hashCode() method will return the same
value for two equal objects.
TopLink / EclipseLink : Do not require the implementation of equals() or hashCode()
in the id class.
@Id
private long companyId
@Id
private long departmentId
...
}
Example id class
...
public class EmployeePK {
private long employeeId;
Embedded Id
An EmbeddedId defines a separate Embeddable Java class to contain the entities primary
key. It is defined through the @EmbeddedId (https:/ / java. sun. com/ javaee/ 5/ docs/ api/
javax/ persistence/ EmbeddedId. html) annotation or <embedded-id> XML element. The
EmbeddedId's Embeddable class must define each id attribute for the entity using Basic
mappings. All attributes in the EmbeddedId's Embeddable are assumed to be part of the
primary key.
The EmbeddedId is also used as the structure passed to the EntityManager find() and
getReference() API. Some JPA products also use the EmbeddedId as a cache key to track
an object's identity. Because of this, it is required (depending on JPA product) to implement
an equals() and hashCode() method on the EmbeddedId. Ensure that the equals()
method checks each part of the primary key, and correctly uses equals for objects and ==
for primitives. Ensure that the hashCode() method will return the same value for two equal
objects.
TopLink / EclipseLink : Do not require the implementation of equals() or hashCode()
in the id class.
@Basic
private long companyId
@Basic
private long departmentId
@OneToOne
@PrimaryKeyJoinColumn(name="OWNER_ID",
referencedColumnName="EMP_ID")
private Employee owner;
...
@Id
private String type;
@ManyToOne
@PrimaryKeyJoinColumn(name="OWNER_ID",
referencedColumnName="EMP_ID")
private Employee owner;
...
Advanced Sequencing
Concurrency and Deadlocks
One issue with table sequencing is that the sequence table can become a concurrency
bottleneck, even causing deadlocks. If the sequence ids are allocated in the same
transaction as the insert, this can cause poor concurrency, as the sequence row will be
locked for the duration of the transaction, preventing any other transaction that needs to
allocate a sequence id. In some cases the entire sequence table or the table page could be
locked causing even transactions allocating other sequences to wait or even deadlock. If a
large sequence pre-allocation size is used this becomes less of an issue, because the
sequence table is rarely accessed. Some JPA providers use a separate (non-JTA) connection
to allocate the sequence ids in, avoiding or limiting this issue. In this case, if you use a JTA
data-source connection, it is important to also include a non-JTA data-source connection in
your persistence.xml.
Customizing
JPA supports three different strategies for generating ids, however there are many other
methods. Normally the JPA strategies are sufficient, so you would only use a different
method in a legacy situation.
Sometimes the application has an application specific strategy for generating ids, such as
prefixing ids with the country code, or branch number. There are several ways to integrate
a customize ids generation strategy, the simplest is just define the id as a normal id and
have the application assign the id value when the object is created.
Some JPA products provide additional sequencing and id generation options, and
configuration hooks.
TopLink, EclipseLink : Several additional sequencing options are provided. A
UnaryTableSequence allows a single column table to be used. A QuerySequence allows
for custom SQL or stored procedures to be used. An API also exists to allow a user to
supply their own code for allocating ids.
Hibernate : A GUID id generation options is provided through the @GenericGenerator
annotation.
TopLink / EclipseLink : Provide a ReturningPolicy that allows for any field values
including the primary key to be returned from the database after an insert or update.
This is defined through the @ReturnInsert, @ReturnUpdate annotations, or the
<return-insert>, <return-update> XML elements in the eclipselink-orm.xml.
No Primary Key
Sometimes your object or table has no primary key. The best solution in this case is
normally to add a generated id to the object and table. If you do not have this option,
sometimes there is a column or set of columns in the table that make up a unique value.
You can use this unique set of columns as your id in JPA. The JPA Id does not always have
to match the database table primary key constraint, nor is a primary key or a unique
constraint required.
If your table truly has no unique columns, then use all of the columns as the id. Typically
when this occurs the data is read-only, so even if the table allows duplicate rows with the
same values, the objects will be the same anyway, so it does not matter that JPA thinks they
are the same object. The issue with allowing updates and deletes is that there is no way to
uniquely identify the object's row, so all of the matching rows will be updated or deleted.
If your object does not have an id, but its' table does, this is fine. Make the object and
Embeddable object, embeddable objects do not have ids. You will need a Entity that
contains this Embeddable to persist and query it.
Inheritance
1 L Accounting 50000
2 S Legal null
@Entity
@DiscriminatorValue("L");
public class LargeProject extends Project {
private BigDecimal budget;
}
Java Persistence/ Print version 37
@Entity
@DiscriminatorValue("S");
public class SmallProject extends Project {
}
Common Problems
ID PROJ_TYPE NAME
1 L Accounting
2 S Legal
SMALLPROJECT (table)
ID
LARGEPROJECT (table)
ID BUDGET
1 50000
...
}
@Entity
@DiscriminatorValue("L");
@Table(name="LARGEPROJECT")
public class LargeProject extends Project {
private BigDecimal budget;
}
@Entity
@DiscriminatorValue("S");
@Table(name="SMALLPROJECT")
public class SmallProject extends Project {
}
Common Problems
The poorest performing queries will be those to the root or branch classes. Avoiding
queries and relationships to the root and branch classes will help to alleviate this
burden. If you must query the root or branch classes there are two methods that JPA
providers use, one is to outer join all of the subclass tables, the second is to first query
the root table, then query only the required subclass table directly. The first method
has the advantage of only requiring one query, the second has the advantage of
avoiding outer joins which typically have poor performance in databases. You may
wish to experiment with each to determine which mechanism is more efficient in your
application and see if your JPA provider supports that mechanism. Typically the
multiple query mechanism is more efficient, but this generally depends on the speed of
your database connection.
TopLink / EclipseLink : Support both querying mechanisms. The multiple query
mechanism is used by default. Outer joins can be used instead through using a
DescriptorCustomizer and the ClassDescriptor's InheritancePolicy's
setShouldOuterJoinSubclasses() method.
Advanced
ID NAME
2 Legal
LARGEPROJECT (table)
ID NAME BUDGET
1 Accounting 50000
@Entity
@Table(name="LARGEPROJECT")
public class LargeProject extends Project {
private BigDecimal budget;
}
@Entity
@Table(name="SMALLPROJECT")
public class SmallProject extends Project {
}
<entity/>
Common Problems
Mapped Superclasses
Mapped superclass inheritance allows inheritance to be used in the object model, when it
does not exist in the data model. It is similar to table per class inheritance, but does not
allow querying, persisting, or relationships to the superclass. Its' main purpose is to allow
mappings information to be inherited by its' subclasses. The subclasses are responsible for
defining the table, id and other information, and can modify any of the inherited mappings.
A common usage of a mapped superclass is to define a common PersistentObject for
your application to define common behavoir and mappings such as the id and version. A
mapped superclass normally should be an abstract class. A mapped superclass is not an
Entity but is instead defined though the @MappedSuperclass (https:/ / java. sun. com/
javaee/ 5/ docs/ api/ javax/ persistence/ MappedSuperclass. html) annotation or the
<mapped-superclass> element.
Java Persistence/ Print version 43
ID NAME
2 Legal
LARGEPROJECT (table)
ID PROJECT_NAME BUDGET
1 Accounting 50000
@Entity
@Table(name="LARGEPROJECT")
@AttributeOverride(name="name", column=@Column(name="PROJECT_NAME"))
public class LargeProject extends Project {
private BigDecimal budget;
}
@Entity
@Table("SMALLPROJECT")
public class SmallProject extends Project {
}
</attribute-override>
...
<entity/>
Common Problems
Embeddables
In an application object model some objects are considered independent, and others are
considered dependent parts of other objects. In UML a relationship to a dependent object is
consider an aggregate or composite association. In a relational database this kind of
relationship could be modeled in two ways, the dependent object could have its own table,
or its data could be embedded in the independent objects table.
In JPA a relationship where the target object's data is embedded in the source object's table
is considered an embedded relationship, and the target object is considered an Embeddable
object. Embeddable objects have different requirements and restrictions than Entity objects
and are defined by the @Embeddable (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ Embeddable. html) annotation or <embeddable> element.
An embeddable object cannot be directly persisted, or queried, it can only be persisted or
queried in the context of its parent. An embeddable object does not have an id or table. The
JPA spec does not support embeddable objects having relationships or inheritance,
although some JPA providers may allow this.
Relationships to embeddable objects are defined through the @Embedded (https:/ / java. sun.
com/ javaee/ 5/ docs/ api/ javax/ persistence/ Embedded. html) annotation or <embedded>
element. The JPA spec only allows references to embeddable objects, and does not support
collection relationships to embeddable objects, although some JPA providers may allow this.
Java Persistence/ Print version 46
@Column(name="END_DATE")
private java.sql.Date endDate;
...
}
Advanced
Sharing
An embeddable object can be shared between multiple classes. Consider a Name object,
that both an Employee and a User contain. Both Employee and a User have their own
tables, with different column names that they desire to store their name in. Embeddables
support this through allowing each embedded mapping to override the columns used in the
embeddable. This is done through the @AttributeOverride (https:/ / java. sun. com/ javaee/
5/ docs/ api/ javax/ persistence/ AttributeOverride. html) annotation or
<attribute-override> element.
Note that an embeddable cannot be shared between multiple instances. If you desire to
share an embeddable object instance, then you must make it an independent object with its
own table.
@Entity
public class User {
@Id
private long id;
...
@Embedded
@AttributeOverrides({
@AttributeOverride(name="startDate", column=@Column(name="SDATE")),
@AttributeOverride(name="endDate", column=@Column(name="EDATE"))
})
private Name name;
...
}
Java Persistence/ Print version 48
Embedded Ids
An EmbeddedId is an embeddable object that contains the Id for an entity.
See: Embedded Id
Nulls
An embeddable object's data is contained in several columns in its parent's table. Since
there is no single field value, there is no way to know if a parent's reference to the
embebbable is null. One could assume that if every field value of the embeddable is null,
then the reference should be null, but then there is no way to represent an embeddable
with all null values. JPA does not allow embeddables to be null, but some JPA providers
may support this.
TopLink / EclipseLink : Support an embedded reference being null. This is set through
using a DescriptorCustomizer and the AggregateObjectMapping
setIsNullAllowed API.
Java Persistence/ Print version 49
Nesting
A nested embeddable is a relationship to an embeddable object from another embeddable.
The JPA spec only allows Basic relationships in an embeddable object, so nested
embeddables are not supported, however some JPA products may support them. Technically
there is nothing preventing the @Emdedded annotation being used in an embeddable object,
so this may just work depending on your JPA provider (don't forget to sacrifice a chicken).
TopLink / EclipseLink : Support embedded mappings from embeddables. The existing
@Embedded annotation or <embedded> element can be used.
A workaround to having a nested embeddable, and for embeddables in general is to use
property access, and add get/set methods for all of the attributes of the nested embeddable
object.
Inheritance
Embeddable inheritance is when one embeddable class subclasses another embeddable
class. The JPA spec does not allow inheritance in embeddable objects, however some JPA
products may support this. Technically there is nothing preventing the
@DiscriminatorColumn annotation being used in an embeddable object, so this may just
work depending on your JPA provider (cross your fingers). Inheritance in embeddables is
always single table as an embeddable must live within its' parent's table. Generally
attempting to mix inheritance between embeddables and entities is not a good idea, but
may work in some cases.
TopLink / EclipseLink : Support inheritance with embeddables. This is set through
using a DescriptorCustomizer and the InheritancePolicy.
Relationships
A relationship is when an embeddable has a OneToOne or other such mapping to an entity.
The JPA spec only allows Basic mappings in an embeddable object, so relationships from
embeddables are not supported, however some JPA products may support them. Technically
there is nothing preventing the @OneToOne annotation or other relationships from being
used in an embeddable object, so this may just work depending on your JPA provider (cross
your fingers).
TopLink / EclipseLink : Support relationship mappings from embeddables. The existing
relationship annotations or XML elements can be used.
Relationships to embeddable objects from entities other than the embeddable's parent are
typically not a good idea, as an embeddable is a private dependent part of its parent.
Generally relationships should be to the embeddable's parent, not the embeddable.
Otherwise, it would normally be a good idea to make the embeddable an independent entity
with its own table. If an embeddable has a bi-directional relationship, such as a OneToMany
that requires an inverse ManyToOne the inverse relationship should be to the enbeddable's
parent.
A workaround to having a relationship from an embeddable is to define the relationship in
the embeddable's parent, and define property get/set methods for the relationship that set
the relationship into the embeddable.
}
public void setEmploymentAddress(Address address) {
getEmploymentDetails().setAddress(address);
}
}
Collections
A collection of embeddable objects is similar to a OneToMany except the target objects are
embeddables and have no Id. This allows for a OneToMany to be defined without a inverse
ManyToOne, as the parent is responsible for storing the foreign key in the target object's
table. JPA 1.0 does not support collections of embeddable objects, but some JPA providers
support this.
TopLink / EclipseLink : Support collections of embeddables. This is set through using a
DescriptorCustomizer and the AggregateCollectionMapping.
Hibernate : Supports collections of embeddables through the @CollectionOfElements
annotation.
Typically the primary key of the target table will be composed of the parent's primary key,
and some unique field in the embeddable object. The embeddable should have a unique
field within its parent's collection, but does not need to be unique for the entire class. It
could still have a unique id and still use sequencing, or if it has no unique fields, its id could
be composed of all of its fields. The embeddable collection object will be different than a
typical embeddable object as it will not be stored in the parent's table, but in its own table.
Embeddables are strictly privately owned objects, deletion of the parent will cause deletion
Java Persistence/ Print version 52
of the embeddables, and removal from the embeddable collection should cause the
embeddable to be deleted. Embeddables cannot be queried directly, and are not
independent objects as they have no Id.
Querying
Embeddable objects cannot be queried directly, but they can be queried in the context of
their parent. Typically it is best to select the parent, and access the embeddable from the
parent. This will ensure the embeddable is registered with the persistence context. If the
embeddable is selected in a query, the resulting objects will be detached, and changes will
not be tracked.
Locking
Locking is perhaps the most ignored persistence consideration. Most applications tend to
ignore thinking about concurrency issues during development, and then smush in a locking
mechanism before going into production. Considering the large percentage of software
projects that fail or are canceled, or never achieve a large user base, perhaps this is logical.
However, locking and concurrency is a critical or at least a very important issue for most
applications, so probably should be something considered earlier in the development cycle.
If the application will have concurrent writers to the same objects, then a locking strategy
is critical so that data corruption can be prevented. There are two strategies for preventing
concurrent modification of the same object/row; optimistic and pessimistic locking.
Technically there is a third strategy, ostrich locking, or no locking, which means put your
head in the sand and ignore the issue.
There are various ways to implement both optimistic and pessimistic locking. JPA has
support for version optimistic locking, but some JPA providers support other methods of
optimistic locking, as well as pessimistic locking.
Locking and concurrency can be a confusing thing to consider, and there are a lot of
misconcepts out there. Correctly implementing locking in your application typically involves
more than setting some JPA or database configuration option (although that is all many
applications that think they are using locking do). Locking may also involve application
level changes, and ensuring other applications accessing the database also do so correctly
for the locking policy being used.
Optimistic Locking
Optimistic locking assumes that the data will not be modified between when you read the
data until you write the data. This is the most common style of locking used and
recommended in today's persistence solutions. The strategy involves checking that one or
more values from the original object read, are still the same when updating it. This verifies
that the object has not changed by another user in between the read and the write.
Java Persistence/ Print version 53
JPA supports using an optimistic locking version field that gets updated on each update.
The field can either be numeric or a timestamp value. A numeric value is recommended as a
numeric value is more precise, portable, performant and easier to deal with than a
timestamp.
The @Version (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ Version.
html) annotation or <version> element is used to define the optimistic lock version field.
The annotation is defined on the version field or property for the object, similar to an Id
mapping. The object must contain an attribute to store the version field.
The object's version attribute is automatically updated by the JPA provider, and should not
normally be modified by the application. The one exception is if the application reads the
object in one transaction, sends the object to a client, and updates/merges the object in
another transaction. In this case the application must ensure that the original object
version is used, otherwise any changes in between the read and write will not be detected.
The EntityManager merge() API will always merge the version, so the application is only
responsible for this if manually merging.
When a locking contention is detected an OptimisticLockException (https:/ / java. sun.
com/ javaee/ 5/ docs/ api/ javax/ persistence/ OptimisticLockException. html) will be thrown.
This could be wrapped insider a RollbackException, or other exceptions if using JTA, but it
should be set as the cause of the exception. The application can handle the exception, but
should normally report the error to the user, and let them determine what to do.
A key point is that when using database pessimistic locking or database transaction
isolation, this will always be the case, the database locks will only occur in step 4, and
any conflicts will not be detected. This is the main reason why using database locking
does not scale to web applications, for the locking to be valid, the database transaction
must be started at step 1 and not committed until step 4. This means the a live
database connection and transaction must be held open while waiting for the web
client, as well as locks, since there is no guarantee that the web client will not sit on
the data for hours, go to lunch, or disappear of the face of the earth, holding database
resources and locking data for all other users can be very undesirable.
For optimistic locking the solution is relatively simple, the object's version must be
sent to the client along with the data (or kept in the http session). When the user
submits the data back, the original version must be merged into the object read from
the database, to ensure that any changes made between step 1 and 4 will be detected.
Paranoid Delusionment
Locking can prevent most concurrency issues, but be careful of going overboard in
over analyzing to death every possible hypothetical occurrence. Sometimes in an
concurrent application (or any software application) bad stuff can happen. Users are
pretty used to this by now, and I don't think anyone out there thinks computer are
perfect.
A good example is a source code control system. Allowing users to overwrite each
other changes is a bad thing; so most systems avoid this through versioning the source
files. If a user submits changes to a file that originated from a older version than the
current version, the source code control system will raise a conflict and make the user
merge the two files. This is essentially optimistic locking. But what if one user
removes, or renames a method in one file, then another user adds a new method or
call in another file to that old method. No source code control system that I know of
will detect this issue, it is a conflict and will cause the build to break. The solution to
this is to start locking or checking the lock on every file in the system (or at least every
possible related file). Similar to using optimistic read locking on every possible related
object, or pessimistically locking every possible related object. This could be done, but
would probably be very expensive, and more importantly would now raise possible
conflicts every time a user checked in, so would be entirely useless.
So, in general be careful of being too paranoid, such that you sacrifice the usability of
your system.
Advanced
Timestamp Locking
Timestamp version locking is supported by JPA and is configured the same as numeric
version locking, except the attribute type will be a java.sql.Timestamp or other date/time
type. Be cautious in using timestamp locking as timestamps have different levels of
precision in different databases, and some database do not store a timestamp's
milliseconds, or do not store them precisely. In general timestamp locking is less efficient
than numeric version locking, so numeric version locking is recommended.
Timestamp locking is frequently used if the table already has a last updated timestamp
column, and is also a convenient way to auto update a last updated column. The timestamp
version value can be more useful than a numeric version, as it includes the relevant
information on when the object was last updated.
The timestamp value in timestamp version locking can either come from the database, or
from Java (mid-tier). JPA does not allow this to be configured, however some JPA providers
may provide this option. Using the database's current timestamp can be very expensive, as
it requires a database call to the server.
Multiple Versions
An object can only have one version in JPA. Even if the object maps to multiple tables, only
the primary table will have the version. If any fields in any of the tables changes, the
version will be updated. If you desire multiple versions, you may need to map multiple
version attributes in your object and manually maintain the duplicate versions, perhaps
through events. Technically there is nothing preventing your from annotating multiple
attributes with @Version, and potentially some JPA providers may support this (don't forget
to sacrifice a chicken).
Cascaded Locking
Locking objects is different than locking rows in the database. An object can be more
complex than a simple row; an object can span multiple tables, have inheritance, have
relationships, and have dependent objects. So determining when an object has changed and
needs to update its' version can be more difficult than determining when a row has
changed.
JPA does define that when any of the object's tables changes the version is updated.
However it is less clear on relationships. If Basic, Embedded, or a foreign key relationship
(OneToOne, ManyToOne) changes, the version will be updated. But what about OneToMany,
ManyToMany, and a target foreign key OneToOne? For changes to these relationships the
update to the version may depend on the JPA provider.
What about changes made to dependent objects? JPA does not have a cascade option for
locking, and has no direct concept of dependent objects, so this is not an option. Some JPA
providers may support this. One way to simulate this is to use write locking. JPA defines the
Java Persistence/ Print version 58
EntityManager lock() (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/
EntityManager. html#lock(java. lang. Object, javax. persistence. LockModeType)) API. You
can define a version only in your root parent objects, and when a child (or relationship) is
changed, you can call the lock API with the parent to cause a WRITE lock. This will cause
the parent version to be updated. You may also be able to automate this through
persistence events.
Usage of cascaded locking depends on your application. If in your application you consider
one user updating one dependent part of an object, and another user updating another part
of the object to be a locking contention, then this is what you want. If your application does
not consider this to be a problem, then you do not want cascaded locking. One of the
advantages of cascaded locking is you have fewer version fields to maintain, and only the
update to the root object needs to check the version. This can make a difference in
optimizations such as batch writing, as the dependent objects may not be able to be
batched if they have their own version that must be checked.
TopLink / EclipseLink : Support cascaded locking through their @OptimisticLocking
and @PrivateOwned annotations and XML.
Field Locking
If you do not have a version field in your table, optimistic field locking is another solution.
Field locking involves comparing certain fields in the object when updating. If those fields
have changed, then the update will fail. JPA does not support field locking, but some JPA
providers do support it.
Field locking can also be used when a finer level of locking is desired. For example if one
user changes the object's name and another changes the objects address, you may desire
for these updates to not conflict, and only desire optimistic lock errors when users change
the same fields. You may also only be concerned about conflicts in changes to certain fields,
and not desire lock errors from conflicts in the other fields.
Field locking can also be used on legacy schemas, where you cannot add a version column,
or to integrate with other applications accessing the same data which are not using
optimistic locking (note if the other applications are not also using field locking, you can
only detect conflicts in one direction).
There are several types of field locking:
• All fields compared in the update - This can lead to a very big where clause, but will
detect any conflicts.
• Selected fields compared in the update - This is useful if conflicts in only certain fields
are desired.
• Changed fields compared in the update - This is useful if only changes to the same fields
are considered to be conflicts.
If your JPA provider does not support field locking, it is difficult to simulate, as it requires
changes to the update SQL. Your JPA provider may allow overriding the update SQL, in
which case, All or Selected field locking may be possible (if you have access to the
original values), but Changed field locking is more difficult because the update must be
dynamic. Another way to simulate field locking is to flush you changes, then refresh the
object using a separate EntityManager and connection and compare the current values
with your original object.
Java Persistence/ Print version 59
When using field locking it is important to keep the original object that was read. If you
read the object in one transaction and send it to a client, then update in another, you are
not really locking. Any changes made between the read and write will not be detected. You
must keep the original object read managed in an EntityManager for your locking to have
any effect.
TopLink / EclipseLink : Support field locking through their @OptimisticLocking
annotation and XML.
Write locking can also be used to provide object-level locks. If you desire for a change to a
dependent object to conflict with any change to the parent object, or any other of its
dependent objects, this can be done through write locking. This can also be used to lock
relationships, when you change a OneToMany or ManyToMany relationship you can also
force the parent's version to be incremented.
In general it is probably best in JPA to enable optimistic locking always, as it is fairly simple
to do, as least in concept, but what does occur on a conflict without any form of locking?
Essentially it is last in wins, so if two users edit the same object, at the same time, the last
one to commit will have their changes reflected in the database. This is true, at least for
users editing the same fields, but if two users edit different fields in the same object, it
depends on the JPA implementation. Some JPA providers only update exactly the fields that
were changed, where as other update all fields in the object. So in one case the first user's
changes would be overridden, but in the second they would not.
Pessimistic Locking
Pessimistic locking means acquiring a lock on the object before you begin to edit the object,
to ensure that no other users are editing the object. Pessimistic locking is typically
implemented through using database row locks, such as through the SELECT ... FOR
UPDATE SQL syntax. The data is read and locked, the changes are made and the transaction
is committed, releasing the locks.
JPA does not support pessimistic locking, but some JPA providers do. It is also possible to
use JPA native SQL queries to issue SELECT ... FOR UPDATE and use pessimistic locking.
When using pessimistic locking you must ensure that the object is refreshed when it is
locked, locking a potentially stale object is of no use. The SQL syntax for pessimistic locking
is database specific, and different databases have different syntax and levels of support, so
ensure your database properly supports your locking requirements.
TopLink / EclipseLink : Support pessimistic locking through the
"eclipselink.pessimistic-lock" query hint.
The main issues with pessimistic locking is they use database resources, so require a
database transaction and connection to be held open for the duration of the edit. This is
typically not desirable for interactive web applications. Pessimistic locking can also have
concurrency issues and cause deadlocks. The main advantages of pessimistic locking is that
once the lock is obtained, it is fairly certain that the edit will be successful. This can be
desirable in highly concurrent applications, where optimistic locking may cause too many
optimistic locking errors.
There are other ways to implement pessimistic locking, it could be implemented at the
application level, or through serializable transaction isolation.
Application level pessimistic locking can be implemented through adding a locked field to
your object. Before an edit you must update the field to locked (and commit the change).
Then you can edit the object, and set the locked field back to false. To avoid conflicts in
acquiring the lock, you should also use optimistic locking, to ensure the lock field is not
updated to true by another user at the same time.
SQL, but this is database specific and different databases have different levels of support.
The main issues with serializable transaction isolation are the same as using SELECT ...
FOR UPDATE (see above for the gory details), in addition everything read is locked, so you
cannot decide to only lock certain objects at certain times, but lock everything all the time.
This can be a major concurrency issue for transactions with common read-only data, and
can lead to deadlocks.
How database implement serializable transaction isolation differs between databases. Some
databases (such as Oracle) can perform serializable transaction isolation in more of an
optimistic sense, than the typically pessimistic implementation. Instead of each transaction
requiring locks on all the data as it is read, the row versions are not checked until the
transaction is committed, if any of the data changed an exception is thrown and the
transaction is not allowed to commit.
Basics
A basic attribute is one where the attribute class is a simple type such as String, Number,
Date or a primitive. A basic attribute's value can map directly to the column value in the
database. The following table summarizes the basic types and the database types they map
to.
Number (BigDecimal, BigInteger, Integer, Double, Long, Float, NUMERIC (NUMBER, INT, LONG, FLOAT,
Short, Byte) DOUBLE)
int, long, float, double, short, byte NUMERIC (NUMBER, INT, LONG, FLOAT,
DOUBLE)
In JPA a basic attribute is mapped through the @Basic (https:/ / java. sun. com/ javaee/ 5/
docs/ api/ javax/ persistence/ Basic. html) annotation or the <basic> element. The types
and conversions supported depend on the JPA implementation and database platform. Some
JPA implementations may support conversion between many different data-types or
additional types, or have extended type conversion support, see the advanced section for
more details. Any basic attribute using a type that does not map directly to a database type
can be serialized to a binary database type.
The easiest way to map a basic attribute in JPA is to do nothing. Any attributes that have no
other annotations and do not reference other entities will be automatically mapped as
Java Persistence/ Print version 62
basic, and even serialized if not a basic type. The column name for the attribute will be
defaulted, named the same as the attribute name, as uppercase. Sometimes auto-mapping
can be unexpected if you have an attribute in your class that you did not intend to have
persisted. You must mark any such non-persistent fields using the @Transient (https:/ /
java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ Transient. html) annotation or
<transient> element.
Although auto-mapping makes rapid prototyping easy, you typically reach a point where
you want control over your database schema. To specify the column name for a basic
attribute the @Column (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/
Column. html) annotation or <column> element is used. The column annotation also allows
for other information to be specified such as the database type, size, and some constraints.
Common Problems
Translating Values
See Conversion
<column name="F_NAME"/>
</basic>
<basic name="lastName">
<column name="L_NAME"/>
</basic>
<transient name="service"/>
</attributes>
</entity>
Truncated Data
A common issue is that data, such as Strings, written from the object are truncated
when read back from the database. This is normally caused by the column length not
being large enough to handle the object's data. In Java there is no maximum size for a
String, but in a database VARCHAR field, there is a maximum size. You must ensure that
the length you set in your column when you create the table is large enough to handle
any object value. For very large Strings CLOBs can be used, but in general CLOBs should
not be over used, as they are less efficient than a VARCHAR.
If you use JPA to generate your database schema, you can set the column length
through the Column annotation or element, see Column Definition and Schema
Generation.
Advanced
Milliseconds
The precision of milliseconds is different for different temporal classes and database types,
and on different databases. The java.util.Date and Calendar classes support
milliseconds. The java.sql.Date and java.sql.Time classes do not support milliseconds.
The java.sql.Timestamp class supports nanoseconds.
On many databases the TIMESTAMP type supports milliseconds. On Oracle prior to Oracle 9,
there was only a DATE type, which was a date and a time, but had no milliseconds. Oracle 9
added a TIMESTAMP type that has milliseconds (and nanoseconds), and now treats the old
DATE type as only a date, so be careful using it as a timestamp. MySQL has DATE, TIME and
DATETIME types. DB2 has a DATE, TIME and TIMESTAMP types, the TIMESTAMP supports
microseconds. Sybase and SQL Server just have a DATETIME type which has milliseconds,
but at least on some versions has precision issues, it seems to store an estimate of the
milliseconds, not the exact value.
If you use timestamp version locking you need to be very careful of your milliseconds
precision. Ensure your database supports milliseconds precisely otherwise you may have
issues, especially if the value is assigned in Java, then differs what gets stored on the
database, which will cause the next update to fail for the same object.
In general I would not recommend using a timestamp and as primary key or for version
locking. There are too many database compatibility issues, as well as the obvious issue of
not supporting two operations in the same millisecond.
Timezones
Temporals become a lot more complex when you start to consider time zones,
internationalization, eras, locals, day-light savings time, etc. In Java only Calendar
supports time zones. Normally a Calendar is assumed to be in the local time zone, and is
stored and retrieved from the database with that assumption. If you then read that same
Calendar on another computer in another time zone, the question is if you will have the
same Calendar or will you have the Calendar of what the original time would have been in
the new time zone? It depends on if the Calendar is stored as the GMT time, or the local
time, and if the time zone was stored in the database.
Some databases support time zones, but most database types do not store the time zone.
Oracle has two special types for timestamps with time zones, TIMESTAMPTZ (time zone is
stored) and TIMESTAMPLTZ (local time zone is used). Some JPA providers may have
extended support for storing Calendar objects and time zones.
TopLink, EclipseLink : Support the Oracle TIMESTAMPTZ and TIMESTAMPLTZ types
using the @TypeConverter annotation and XML.
Forum Posts
• Investigation of storing timezones in MySQL (http:/ / www. nabble. com/
MySQL's-datetime-and-time-zones--td21006801. html)
Java Persistence/ Print version 66
Enums
Java Enums (https:/ / java. sun. com/ java/ 5/ docs/ api/ java/ lang/ Enum. html) are typically
used as constants in an object model. For example an Employee may have a gender of
enum type Gender (MALE, FEMALE).
By default in JPA an attribute of type Enum will be stored as a Basic to the database, using
the integer Enum values as codes (i.e. 0, 1). JPA also defines an @Enumerated (https:/ /
java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ Enumerated. html) annotation and
<enumerated> element (on a <basic>) to define an Enum attribute. This can be used to
store the Enum as the STRING value of its name (i.e. "MALE", "FEMALE").
For translating Enum types to values other than the integer or String name, such as
character constants, see Translating Values.
@Entity
public class Employee {
...
@Basic
@Enumerated(STRING)
private Gender gender;
...
}
By default in JPA any Serializable attribute that is not a relationship or a basic type
(String, Number, temporal, primitive), will be serialized to a BLOB field.
JPA defines the @Lob (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ Lob.
html) annotation and <lob> element (on a <basic>) to define that an attribute maps to a
LOB type in the database. The annotation is just a hint to the JPA implementation that this
attribute will be stored in a LOB, as LOBs may need to be persisted specially. Sometimes
just mapping the LOB as a normal Basic will work fine as well.
Various databases and JDBC drivers have various limits for LOB sizes. Some JDBC drivers
have issues beyond 4k, 32k or 1meg. The Oracle thin JDBC drivers had a 4k limitation in
some versions for binding LOB data. Oracle provided a workaround for this limitation,
which some JPA providers support. For reading LOBs, some JDBC drivers prefer using
streams, some JPA providers also support this option.
Typically the entire LOB will be read and written for the attribute. For very large LOBs
reading the value always, or reading the entire value may not be desired. The fetch type of
the Basic could be set to LAZY to avoid reading a LOB unless accessed. Support for LAZY
fetching on Basic is optional in JPA, so some JPA providers may not support it. A
workaround, which is often a good idea in general given the large performance cost of
LOBs, is to store the LOB in a separate table and class and define a OneToOne to the LOB
object instead of a Basic. If the entire LOB is never desired to be read, then it should not be
mapped. It is best to use direct JDBC to access and stream the LOB in this case. In may be
possible to map the LOB to a java.sql.Blob/java.sql.Clob in your object to avoid
reading the entire LOB, but these require a live connection, so may have issues with
detached objects.
Lazy Fetching
The fetch attribute can be set on a Basic mapping to use LAZY fetching. By default all
Basic mappings are EAGER, which means the column is selected whenever the object is
selected. By setting the fetch to LAZY, the column will not be selected with the object. If
the attribute is accessed, then the attribute value will be selected in a separate database
select. Support for LAZY is an optional feature of JPA, so some JPA providers may not
support it. Typically support for lazy on basics will require some form of byte code weaving,
or dynamic byte code generation, which may have issues in certain environments or JVMs,
or may require preprocessing your application's persistence unit jar.
Only attributes that are rarely accessed should be marked lazy, as accessing the attribute
causes a separate database select, which can hurt performance. This is especially true if a
large number of objects is queried. The original query will require one database select, but
if each object's lazy attribute is accessed, this will require n database selects, which can be
a major performance issue.
Using lazy fetching on basics is similar to the concept of fetch groups. Lazy basics is
basically support for a single default fetch group. Some JPA providers support fetch groups
in general, which allow more sophisticated control over what attributes are fetched per
query.
TopLink, EclipseLink : Support lazy basics and fetch groups. Fetch groups can be
configured through the EclipseLink API using the FetchGroup class.
Optional
A Basic attribute can be optional if its value is allowed to be null. By default everything
is assumed to be optional, except for an Id, which can not be optional. Optional is basically
only a hint that applies to database schema generation, if the persistence provider is
configured to generate the schema. It adds a NOT NULL constraint to the column if false.
Some JPA providers also perform validation of the object for optional attributes, and will
throw a validation error before writing to the database, but this is not required by the JPA
specification. Optional is defined through the optional attribute of the Basic annotation
or element.
a unique constraint on the column, most JPA providers will automatically define primary
key and foreign key constraints based on the Id and relationship mappings.
JPA does not define any options to define an index. Some JPA providers may provide
extensions for this. You can also create your own indexes through native queries
</attributes>
</entity>
Conversion
A common problem in storing values to the database is that the value desired in Java differs
from the value used in the database. Common examples include using a boolean in Java
and a 0, 1 or a 'T', 'F' in the database. Other examples are using a String in Java and a
DATE in the database.
One way to accomplish this is to translate the data through property get/set methods.
@Entity
public class Employee {
...
private boolean isActive;
...
@Transient
public boolean getIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
@Basic
private String getIsActiveValue() {
if (isActive) {
return "T";
} else {
return "F";
Java Persistence/ Print version 71
}
}
private void setIsActiveValue(String isActive) {
this.isActive = "T".equals(isActive);
}
}
Custom Types
JPA defines support for most common database types, however some databases and JDBC
driver have additional types that may require additional support.
Some custom database types include:
• TIMESTAMPTZ, TIMESTAMPLTZ (Oracle)
• TIMESTAMP WITH TIMEZONE (Postgres)
• XMLTYPE (Oracle)
• XML (DB2)
• NCHAR, NVARCHAR, NCLOB (Oracle)
• Struct (STRUCT Oracle)
• Array (VARRAY Oracle)
• BINARY_INTEGER, DEC, INT, NATURAL, NATURALN, BOOLEAN (Oracle)
• POSITIVE, POSITIVEN, SIGNTYPE, PLS_INTEGER (Oracle)
• RECORD, TABLE (Oracle)
• SDO_GEOMETRY (Oracle)
• LOBs (Oracle thin driver)
To handle persistence to custom database types either custom hooks are required in your
JPA provider, or you need to mix raw JDBC code with your JPA objects. Some JPA provider
provide custom support for many custom database types, some also provide custom hooks
for adding your own JDBC code to support a custom database type.
TopLink, EclipseLink : Support several custom database types including,
TIMESTAMPTZ, TIMESTAMPLTZ, XMLTYPE, NCHAR, NVARCHAR, NCLOB,
object-relational Struct and Array types, PLSQL types, SDO_GEOMETRY and LOBs.
Relationships
A relationship is a reference from one object to another. In Java, relationships are defined
through object references (pointers) from a source object to the target object. Technically,
in Java there is no difference between a relationship to another object and a "relationship"
to a data attribute such as a String or Date (primitives are different), as both are
pointers; however, logically and for the sake of persistence, data attributes are considered
part of the object, and references to other persistent objects are considered relationships.
In a relational database relationships are defined through foreign keys. The source row
contains the primary key of the target row to define the relationship (and sometimes the
Java Persistence/ Print version 72
inverse). A query must be performed to read the target objects of the relationship using the
foreign key and primary key information.
In Java, if a relationship is to a collection of other objects, a Collection or array type is
used in Java to hold the contents of the relationship. In a relational database, collection
relations are either defined by the target objects having a foreign key back to the source
object's primary key, or by having an intermediate join table to store the relationship (both
objects' primary keys).
All relationships in Java and JPA are unidirectional, in that if a source object references a
target object there is no guarantee that the target object also has a relationship to the
source object. This is different than a relational database, in which relationships are
defined through foreign keys and querying such that the inverse query always exists.
Lazy Fetching
The cost of retrieving and building an object's relationships, far exceeds the cost of
selecting the object. This is especially true for relationships such as manager or
managedEmployees such that if any employee were selected it would trigger the loading of
every employee through the relationship hierarchy. Obviously this is a bad thing, and yet
having relationships in objects is very desirable.
The solution to this issue is lazy fetching (lazy loading). Lazy fetching allows the fetching of
a relationship to be deferred until it is accessed. This is important not only to avoid the
database access, but also to avoid the cost of building the objects if they are not needed.
In JPA lazy fetching can be set on any relationship using the fetch attribute. The fetch
can be set to either LAZY or EAGER as defined in the FetchType (https:/ / java. sun. com/
javaee/ 5/ docs/ api/ javax/ persistence/ FetchType. html) enum. The default fetch type is
LAZY for all relationships except for OneToOne and ManyToOne, but in general it is a good
idea to make every relationship LAZY. The EAGER default for OneToOne and ManyToOne is
for implementation reasons (more difficult to implement), not because it is a good idea.
Technically in JPA LAZY is just a hint, and a JPA provider is not required to support it,
however in reality all main JPA providers support it, and they would be pretty useless if
they did not.
Java Persistence/ Print version 73
Magic
Lazy fetching normally involves some sort of magic in the JPA provider to transparently
fault in the relationships as they are accessed. The typical magic for collection relationships
is for the JPA provider to set the relationships to its own Collection, List, Set or Map
implementation. When any (or most) method is accessed on this collection proxy, it loads
the real collection and forwards the method. This is why JPA requires that all collection
relationships use one of the collection interfaces (although some JPA providers support
collection implementations too).
For OneToOne and ManyToOne relationships the magic normally involves some sort of byte
code manipulation of the entity class, or creation of a subclass. This allows the access to the
field or get/set methods to be intercepted, and for the relationships to be first retrieved
before allowing access to the value. Some JPA providers use different methods, such as
wrapping the reference in a proxy object, although this can have issues with null values
and primitive methods. To perform the byte code magic normally an agent or
post-processor is required. Ensure that you correctly use your providers agent or
post-processor otherwise lazy may not work. You may also notice additional variables when
in a debugger, but in general debugging will still work as normal.
Java Persistence/ Print version 74
Basics
A Basic attribute can also be made LAZY, but this is normally a different mechanism than
lazy relationships, and should normally be avoided unless the attribute is rarely accessed.
See Basic Attributes : Lazy Fetching.
just because you want two collection relationships loaded, does not mean you want them
join fetch which would result in a very inefficient join that would return n^2 data.
Join fetching is something that JPA currently only provides through JPQL, which is normally
the correct place for it, as each use case has different relationship requirements. Some JPA
providers also provider a join fetch option at the mapping level to always join fetch a
relationship, but this is normally not the same thing as EAGER. Join fetching is not normally
the most efficient way to load a relationship anyway, normally batch reading a relationship
is much more efficient when supported by your JPA provider.
See Join Fetching
See Batch Reading
Cascading
Relationship mappings have a cascade option that allows the relationship to be cascaded
for common operations. cascade is normally used to model dependent relationships, such
as Order -> OrderLine. Cascading the orderLines relationship allows for the Order's ->
OrderLines to be persisted, removed, merged along with their parent.
The following operations can be cascaded, as defined in the CascadeType (https:/ / java.
sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ CascadeType. html) enum:
• PERSIST - Cascaded the EntityManager.persist() operation. If persist() is called on
the parent, and the child is also new, it will also be persisted. If it is existing, nothing will
occur, although calling persist() on an existing object will still cascade the persist
operation to its dependents. If you persist an object, and it is related to a new object, and
the relationship does not cascade persist, then an exception will occur. This may require
that you first call persist on the related object before relating it to the parent. General it
may seem odd, or be desirable to always cascade the persist operation, if a new object is
related to another object, then it should probably be persisted. There is most likely not a
major issue with always cascading persist on every relationship, although it may have an
impact on performance. Calling persist on a related object is not required, on commit any
related object whose relationship is cascade persist will automatically be persisted. The
advantage of calling persist up front is that any generated ids will (unless using identity)
be assigned, and the prePersist event will be raised.
• REMOVE - Cascaded the EntityManager.remove() operation. If remove() is called on the
parent then the child will also be removed. This should only be used for dependent
relationships. Note that only the remove() operation is cascaded, if you remove a
dependent object from a OneToMany collection it will not be deleted, JPA requires that
you explicitly call remove() on it. Some JPA providers may support an option to have
objects removed from dependent collection deleted, JPA 2.0 also defines an option for
this.
• MERGE - Cascaded the EntityManager.merge() operation. If merge() is called on the
parent, then the child will also be merged. This should normally be used for dependent
relationships. Note that this only effects the cascading of the merge, the relationship
reference itself will always be merged. This can be a major issue if you use transient
variables to limit serialization, you may need to manually merge, or reset transient
relationships in this case. Some JPA providers provide additional merge operations.
• REFRESH - Cascaded the EntityManager.refresh() operation. If refresh() is called on
the parent then the child will also be refreshed. This should normally be used for
Java Persistence/ Print version 76
dependent relationships. Be careful enabling this for all relationships, as it could cause
changes made to other objects to be reset.
• ALL - Cascaded all the above operations.
Target Entity
Relationship mappings have a targetEntity attribute that allows the reference class
(target) of the relationship to be specified. This is normally not required to be set as it is
defaulted from the field type, get method return type, or collection's generic type.
This can also be used if your field uses a public interface type, for example field is interface
Address, but the mapping needs to be to implementation class AddressImpl. Another usage
is if your field is a superclass type, but you want to map the relationship to a subclass.
...
}
Collections
Collection mappings include OneToMany, ManyToMany, and in JPA 2.0 ElementCollection.
JPA requires that the type of the collection field or get/set methods be one of the Java
collection interfaces, Collection, List, Set, or Map.
Collection Implementations
Your field should not be of a collection implementation type, such as ArrayList. Some JPA
providers may support using collection implementations, many support EAGER collection
relationships to use the implementation class. You can set any implementation as the
instance value of the collection, but when reading an object from the database, if it is LAZY
the JPA provider will normally put in a special LAZY collection.
Duplicates
A List in Java supports duplicate entries, and a Set does not. In the database, duplicates
are generally not supported. Technically it could be possible if a JoinTable is used, but JPA
does not require duplicates to be supported, and most providers do not.
If you require duplicate support, you may need to create an object that represents and
maps to the join table. This object would still require a unique Id, such as a
GeneratedValue. See Mapping a Join Table with Additional Columns.
Ordering
JPA allows the collection values to be ordered by the database when retrieved. This is done
through the @OrderBy (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/
OrderBy. html) annotation or <order-by> XML element.
The value of the OrderBy is a JPQL ORDER BY string. The can be an attribute name followed
by ASC or DESC for ascending or descending ordering. You could also use a path or nested
attribute, or a "," for multiple attributes. If no OrderBy value is given it is assumed to be
the Id of the target object.
The OrderBy value must be a mapped attribute of the target object. If you want to have an
ordered List you need to add an index attribute to your target object and an index column
to it's table. You will also have to ensure you set the index values. JPA 2.0 will have
extended support for an ordered List using an OrderColumn.
Java Persistence/ Print version 78
Note that using an OrderBy does not ensure the collection is ordered in memory. You are
responsible for adding to the collection in the correct order. Java does define a SortedSet
interface and TreeSet collection implementation that does maintain an order. JPA does not
specifically support SortedSet, but some JPA providers may allow you to use a SortedSet
or TreeSet for your collection type, and maintain the correct ordering. By default these
require your target object to implement the Comparable interface, or set a Comparator.
You can also use the Collections.sort() method to sort a List when required. One
option to sort in memory is to use property access and in your set and add methods call
Collections.sort().
Common Problems
Object corruption, one side of the relationship is not updated after updating the
other side
A common problem with bi-directional relationships is the application updates one side of
the relationship, but the other side does not get updated, and becomes out of synch. In JPA,
as in Java in general it is the responsibility of the application, or the object model to
maintain relationships. If your application adds to one side of a relationship, then it must
add to the other side.
This is commonly resolved through add or set methods in the object model that handle
both sides of the relationships, so the application code does not need to worry about it.
There are two ways to go about this, you can either only add the relationship maintenance
code to one side of the relationship, and only use the setter from one side (such as making
the other side protected), or add it to both sides and ensure you avoid a infinite loop.
For example:
...
}
Some JPA providers also provide static weaving instead, or in addition to dynamic weaving.
For static weaving some preprocessor must be run on your JPA classes.
When running in JEE lazy should normally work, as the class loader hook is required by the
EJB specification. However some JEE providers may not support this, so static weaving may
be required.
Also ensure that you are not accessing the relationship when you shouldn't be. For example
if you use property access, and in your set method access the related lazy value, this will
cause it to be loaded. Either remove the set method side-effects, or use field access.
Advanced
Advanced Relationships
Maps
Java defines the Map interface to represent collections whose values are indexed on a key.
There are several Map implementations, the most common is HashMap, but also Hashtable
and TreeMap.
JPA allows a Map to be used for any collection mapping including, OneToMany, ManyToMany
and ElementCollection. JPA requires that the Map interface be used as the attribute type,
although some JPA providers may also support using Map implementations.
In JPA 1.0 the map key must be a mapped attribute of the collection values. The @MapKey
(https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ MapKey. html) annotation
or <map-key> XML element is used to define a map relationship. If the MapKey is not
specified it defaults to the target object's Id.
Java Persistence/ Print version 83
@Entity
public class PhoneNumber {
@Id
private long id;
@Basic
private String type; // Either "home", "work", or "fax".
...
@ManyToOne
private Employee owner;
...
}
@Entity
public class PhoneNumber {
@Id
private long id;
...
@ManyToOne
private Employee owner;
...
}
@Entity
public class PhoneNumber {
@Id
private long id;
...
@ManyToOne
private Employee owner;
...
}
@Entity
public class PhoneType {
@Id
private long id;
...
@Basic
private String type;
...
}
Java Persistence/ Print version 86
@Entity
public class PhoneNumber {
@Id
private long id;
...
}
@Embeddable
public class PhoneType {
@Basic
private String type;
...
}
Java Persistence/ Print version 87
Join Fetching
Join fetching is a query optimization technique for reading multiple objects in a single
database query. It involves joining the two object's tables in SQL and selecting both object's
data. Join fetching is commonly used for OneToOne relationships, but also can be used for
any relationship including OneToMany and ManyToMany.
Join fetching is one solution to the classic ORM n+1 performance problem. The issue is if
you select n Employee objects, and access each of their addresses, in basic ORM (including
JPA) you will get 1 database select for the Employee objects, and then n database selects,
one for each Address object. Join fetching solves this issue by only requiring one select,
and selecting both the Employee and its Address.
JPA supports join fetching through JPQL using the JOIN FETCH syntax.
This causes both the Employee and Address data to be selected in a single query.
Outer Joins
Using the JPQL JOIN FETCH syntax a normal INNER join is performed. This has the side
effect of filtering any Employee from the result set that did not have an address. An OUTER
join in SQL is one that does not filter absent rows on the join, but instead joins a row of all
null values. If your relationship allows null or an empty collection for collection
relationships, then you can use an OUTER join fetch, this is done in JPQL using the LEFT
syntax.
Java Persistence/ Print version 88
Note that OUTER joins can be less efficient on some databases, so avoid using an OUTER if it
is not required.
Nested Joins
JPA 1.0 does not allow nested join fetches in JPQL, although this may be supported by some
JPA providers. You can join fetch multiple relationships, but not nested relationships.
Batch Reading
Batch Reading is a query optimization technique for reading multiple related objects in a
finite set of database queries. It involves executing the query for the root objects as normal.
But for the related objects the original query is joined with the query for the related
objects, allowing all of the related objects to be read in a single database query. Batch
Reading can be used for any type of relationship.
Batch Reading is one solution to the classic ORM n+1 performance problem. The issue is if
you select n Employee objects, and access each of their addresses, in basic ORM (including
JPA) you will get 1 database select for the Employee objects, and then n database selects,
one for each Address object. Batch Reading solves this issue by requiring one select for the
Employee objects and one select for the Address objects.
Batch reading is more optimal for reading collection relationships and multiple
relationships as it does not require selecting duplicate data as in join fetching.
JPA does not support batch reading, but some JPA providers do.
TopLink, EclipseLink : Support a "eclipselink.batch" query hint to enable batch
reading. Batch reading can also be configured on a relationship mapping using the
API.
OneToOne
A OneToOne relationship in Java is where the source object has an attribute that references
another target object and (if) that target object had the inverse relationship back to the
source object it would also be a OneToOne relationship. All relationships in Java and JPA are
unidirectional, in that if a source object references a target object there is no guarantee
that the target object also has a relationship to the source object. This is different than a
relational database, in which relationships are defined through foreign keys and querying
such that the inverse query always exists.
JPA also defines a ManyToOne relationship, which is similar to a OneToOne relationship
except that the inverse relationship (if it were defined) is a OneToMany relationship. The
main difference between a OneToOne and a ManyToOne relationship in JPA is that a
ManyToOne always contains a foreign key from the source object's table to the target
object's table, where as a OneToOne relationship the foreign key may either be in the source
object's table or the target object's table. If the foreign key is in the target object's table
JPA requires that the relationship be bi-directional (must be defined in both objects), and
the source object must use the mappedBy attribute to define the mapping.
In JPA a OneToOne relationship is defined through the @OneToOne (https:/ / java. sun. com/
javaee/ 5/ docs/ api/ javax/ persistence/ OneToOne. html) annotation or the <one-to-one>
element. A OneToOne relationship typically requires a @JoinColumn (https:/ / java. sun.
com/ javaee/ 5/ docs/ api/ javax/ persistence/ JoinColumn. html).
Java Persistence/ Print version 91
See Also
• Relationships
• Cascading
• Lazy Fetching
• Target Entity
• Join Fetching
• Batch Reading
• Common Problems
• ManyToOne
Common Problems
Foreign key is also part of the primary key.
See Primary Keys through OneToOne Relationships.
It can also occur if your JPA provider does not support referential integrity, or does not
resolve bi-directional constraints. In this case you may either need to remove the
constraint, or use EntityManager flush() to ensure the order your objects are
written in.
Advanced
This may work in some JPA providers, others may require different configuration, or not
support this type of data model.
@Id
@Column(name="DEP_ID" insertable=false, updateable=false)
private long departmentId;
@Id
@Column(name="COM_ID" insertable=false, updateable=false)
private long companyId;
...
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="COM_ID")
private Company company;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="DEP_ID")
@PrimaryKeyJoinColumn(name="COM_ID")
private Department department;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="MNG_ID")
@PrimaryKeyJoinColumn(name="DEP_ID")
@PrimaryKeyJoinColumn(name="COM_ID")
private Employee manager;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="ADD_ID")
@PrimaryKeyJoinColumn(name="EMP_ID")
@PrimaryKeyJoinColumn(name="DEP_ID")
@PrimaryKeyJoinColumn(name="COM_ID")
private Address address;
...
}
ManyToOne
A ManyToOne relationship in Java is where the source object has an attribute that
references another target object and (if) that target object had the inverse relationship
back to the source object it would be a OneToMany relationship. All relationships in Java and
JPA are unidirectional, in that if a source object references a target object there is no
guarantee that the target object also has a relationship to the source object. This is
different than a relational database, in which relationships are defined through foreign keys
and querying such that the inverse query always exists.
JPA also defines a OneToOne relationship, which is similar to a ManyToOne relationship
except that the inverse relationship (if it were defined) is a OneToOne relationship. The
main difference between a OneToOne and a ManyToOne relationship in JPA is that a
ManyToOne always contains a foreign key from the source object's table to the target
object's table, where as a OneToOne relationship the foreign key may either be in the source
object's table or the target object's table.
In JPA a ManyToOne relationship is defined through the @ManyToOne (https:/ / java. sun.
com/ javaee/ 5/ docs/ api/ javax/ persistence/ ManyToOne. html) annotation or the
<many-to-one> element.
In JPA a ManyToOne relationship is always (well almost always) required to define a
OneToMany relationship, the ManyToOne always defines the foreign key (JoinColumn) and
the OneToMany must use a mappedBy to define its inverse ManyToOne.
Java Persistence/ Print version 98
See Also
• Relationships
• Cascading
• Lazy Fetching
• Target Entity
• Join Fetching
• Batch Reading
• Common Problems
• OneToOne
• OneToMany
Common Problems
Foreign key is also part of the primary key.
See Primary Keys through OneToOne Relationships.
See Target Foreign Keys, Primary Key Join Columns, Cascade Primary Keys.
It can also occur if your JPA provider does not support referential integrity, or does not
resolve bi-directional constraints. In this case you may either need to remove the
constraint, or use EntityManager flush() to ensure the order your objects are
written in.
Advanced
OneToMany
Java Persistence/ Print version 100
A OneToMany relationship in Java is where the source object has an attribute that stores a
collection of target objects and (if) those target objects had the inverse relationship back to
the source object it would be a ManyToOne relationship. All relationships in Java and JPA
are unidirectional, in that if a source object references a target object there is no guarantee
that the target object also has a relationship to the source object. This is different than a
relational database, in which relationships are defined through foreign keys and querying
such that the inverse query always exists.
JPA also defines a ManyToMany relationship, which is similar to a OneToMany relationship
except that the inverse relationship (if it were defined) is a ManyToMany relationship. The
main difference between a OneToMany and a ManyToMany relationship in JPA is that a
ManyToMany always makes use of a intermediate relational join table to store the
relationship, where as a OneToMany can either use a join table, or a foreign key in target
object's table referencing the source object table's primary key. If the OneToMany uses a
foreign key in the target object's table JPA requires that the relationship be bi-directional
(inverse ManyToOne relationship must be defined in the target object), and the source
object must use the mappedBy attribute to define the mapping.
In JPA a OneToMany relationship is defined through the @OneToMany (https:/ / java. sun.
com/ javaee/ 5/ docs/ api/ javax/ persistence/ OneToMany. html) annotation or the
<one-to-many> element.
Join Table
A common mismatch between objects and relational tables is that a OneToMany does not
require a back reference in Java, but requires a back reference foreign key in the database.
Normally it is best to define the ManyToOne back reference in Java, if you cannot or don't
want to do this, then you can use a intermediate join table to store the relationship. This is
similar to a ManyToMany relationship, but if you add a unique constraint to the target
foreign key you can enforce that it is OneToMany.
JPA defines a join table using the @JoinTable (https:/ / java. sun. com/ javaee/ 5/ docs/ api/
javax/ persistence/ JoinTable. html) annotation and <join-table> XML element. A
JoinTable can be used on a ManyToMany or OneToMany mappings.
See also, Undirectional OneToMany
Java Persistence/ Print version 101
Some expect the JPA provider to have magic that automatically maintains relationships.
This was actually part of the EJB CMP 2 specification. However the issue is if the objects
are detached or serialized to another VM, or new objects are related before being managed,
or the object model is used outside the scope of JPA, then the magic is gone, and the
application is left figuring things out, so in general it may be better to add the code to the
object model. However some JPA providers do have support for automatically maintaining
relationships.
In some cases it is undesirable to instantiate a large collection when adding a child object.
One solution is to not map the bi-directional relationship, and instead query for it as
required. Also some JPA provides optimize their lazy collection objects to handle this case,
so you can still add to the collection without instantiating it.
See Also
• Relationships
• Cascading
• Lazy Fetching
• Target Entity
• Collections
• Maps
• Join Fetching
• Batch Reading
• Common Problems
• ManyToOne
• ManyToMany
Common Problems
Object not in collection after refresh.
See Object corruption.
Advanced
ManyToMany
A ManyToMany relationship in Java is where the source object has an attribute that stores a
collection of target objects and (if) those target objects had the inverse relationship back to
the source object it would also be a ManyToMany relationship. All relationships in Java and
JPA are unidirectional, in that if a source object references a target object there is no
guarantee that the target object also has a relationship to the source object. This is
different than a relational database, in which relationships are defined through foreign keys
and querying such that the inverse query always exists.
JPA also defines a OneToMany relationship, which is similar to a ManyToMany relationship
except that the inverse relationship (if it were defined) is a ManyToOne relationship. The
main difference between a OneToMany and a ManyToMany relationship in JPA is that a
ManyToMany always makes use of a intermediate relational join table to store the
relationship, where as a OneToMany can either use a join table, or a foreign key in target
object's table referencing the source object table's primary key.
In JPA a ManyToMany relationship is defined through the @ManyToMany (https:/ / java. sun.
com/ javaee/ 5/ docs/ api/ javax/ persistence/ ManyToMany. html) annotation or the
<many-to-many> element.
All ManyToMany relationships require a JoinTable. The JoinTable is defined using the
@JoinTable (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ JoinTable.
html) annotation and <join-table> XML element. The JoinTable defines a foreign key to
the source object's primary key (joinColumns), and a foreign key to the target object's
primary key (inverseJoinColumns). Normally the primary key of the JoinTable is the
combination of both foreign keys.
@ManyToMany
@JoinTable(
name="EMP_PROJ"
joinColumns={@JoinColumn(name="EMP_ID",
referencedColumnName="EMP_ID")}
inverseJoinColumns={@JoinColumn(name="PROJ_ID",
referencedColumnName="PROJ_ID")})
private List<Project> projects;
...
}
See Also
• Relationships
• Cascading
• Lazy Fetching
• Target Entity
• Collections
• Maps
• Join Fetching
• Batch Reading
• Common Problems
• OneToMany
Java Persistence/ Print version 106
Common Problems
Object not in collection after refresh.
If you have a bi-directional ManyToMany relationship, ensure that you add to both sides
of the relationship.
See Object corruption.
Advanced
@Entity
public class Project {
@Id
private long id;
...
@OneToMany
private List<ProjectAssociation> employees;
...
// Add an employee to the project.
// Create an association object for the relationship and set its'
data.
public void addEmployee(Employee employee, boolean teamLead) {
ProjectAssociation association = new ProjectAssociation();
association.setEmployee(employee);
association.setProject(this);
association.setEmployeeId(employee.getId());
association.setProjectId(this.getId());
association.setIsTeamLead(teamLead);
employees.add(association);
}
}
@Entity
@Table(name="PROJ_EMP")
@IdClass(ProjectAssociationId.class)
public class ProjectAssociation {
@Id
private long employeeId;
@Id
private long projectId;
@Column("IS_PROJECT_LEAD")
private boolean isProjectLead;
@ManyToOne
@PrimaryKeyJoinColumn(name="EMPLOYEEID", referencedColumnName="ID")
private Employee employee;
@ManyToOne
@PrimaryKeyJoinColumn(name="PROJECTID", referencedColumnName="ID")
Java Persistence/ Print version 108
Runtime
Once you have mapped your object model the second step in persistence development is to
access and process your objects from your application, this is referred to as the runtime
usage of persistence. Various persistence specifications have had various runtime models.
The most common model is to have a runtime API; a runtime API typically will define API
for connecting to a data-source, querying and transactions.
Entity Manager
JPA provides a runtime API defined by the javax.persistence (https:/ / java. sun. com/
javaee/ 5/ docs/ api/ javax/ persistence/ package-summary. html) package. The main
runtime class is the EntityManager (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ EntityManager. html) class. The EntityManager provides API for creating
queries, accessing transactions, and finding, persisting, merging and deleting objects. The
JPA API can be used in any Java environment including JSE and JEE.
An EntityManager can be created through an EntityManagerFactory (https:/ / java. sun.
com/ javaee/ 5/ docs/ api/ javax/ persistence/ EntityManagerFactory. html), or can be
injected into an instance variable in an EJB SessionBean, or can be looked up in JNDI in a
JEE server.
JPA is used differently in Java Standard Edition (JSE) versus Java Enterprise Edition (JEE).
The JPA application is typically required to be packaged into a persistence unit jar file. This
is a normal jar, that has the persistence.xml file in the META-INF directory. Typically a
JPA provider will require something special be done in JSE to enable certain features such
as lazy fetching, such as static weaving (byte-code processing) of the jar, or using an agent
JVM option.
In JSE the EntityManager must be closed when your application is done with it. The
life-cycle of the EntityManager is typically per client, or per request. The
EntityManagerFactory can be shared among multiple threads or users, but the
EntityManager should not be shared.
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
persistence_1_0.xsd"
version="1.0">
<persistence-unit name="acme" transaction-type="RESOURCE_LOCAL">
<provider>org.acme.jpa.PersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="acme.driver" value="org.acme.db.Driver"/>
<property name="acme.url" value="jdbc:acmedb://localhost/acme"/>
<property name="acme.user" value="acmeuser"/>
<property name="acme.password" value="loonytunes"/>
</properties>
</persistence-unit>
</persistence>
@PersistenceContext(unitName="acme")
private EntityManager entityManager;
@PersistenceUnit(unitName="acme")
private EntityManagerFactory factory;
...
}
Querying
Querying is a fundamental part of persistence. Being able to persist something is not very
useful without being able to query it back. There are many querying languages and
frameworks; the most common query language is SQL used in relational databases. JPA
uses the Java Persistence Querying Language (JPQL), which is based on the SQL language
and evolved from the EJB Query Language (EJBQL). It basically provides the SQL syntax at
the object level instead of at the data level.
Other querying languages and frameworks include:
• SQL
• EJBQL
• JDOQL
• Query By Example (QBE)
• TopLink Expressions
• Hibernate Criteria
• Object Query Language (OQL)
JPA provides querying through JPQL, the Query interface, and the @NamedQuery annotation
and <named-query> element.
JPQL is similar in syntax to SQL and can be defined through its BNF definition.
Java Persistence/ Print version 112
Named Queries
There are two main types of queries in JPA, named queries and dynamic queries. A named
query is used for a static query that will be used many times in the application. The
advantage of a named query is that it can be defined once, in one place, and reused in the
application. Most JPA providers also pre-parse/compile named queries, so they are more
optimized than dynamic queries which typically must be parsed/compiled every time they
are executed. Since named queries are part of the persistence meta-data they can also be
optimized or overridden in the orm.xml without changing the application code.
Named queries are defined through the @NamedQuery (https:/ / java. sun. com/ javaee/ 5/
docs/ api/ javax/ persistence/ NamedQuery. html) and @NamedQueries (https:/ / java. sun.
com/ javaee/ 5/ docs/ api/ javax/ persistence/ NamedQueries. html) annotations, or
<named-query> XML element.
Named queries can be defined on any annotated class, but are typically defined on the
Entity that they query for. The name of the named query must be unique for the entire
persistence unit, they name is not local to the Entity. In the orm.xml named queries can be
defined either on the <entity-mappings> or on any <entity>.
Named queries are typically parametrized, so they can be executed with different
parameter values. Parameters are defined in JPQL using the :<name> syntax for named
parameters, or the ? syntax for positional parameters.
A collection of query hints can also be provided to a named query. Query hints can be used
to optimize or to provide special configuration to a query. Query hints are specific to the
JPA provider. Query hints are defined through the @QueryHint (https:/ / java. sun. com/
javaee/ 5/ docs/ api/ javax/ persistence/ QueryHint. html) annotation or query-hint XML
element.
</entity>
</entity-mappings>
Dynamic Queries
Dynamic queries are normally used when the query depends on the context. For example,
depending on which items in the query form were filled in, the query may have different
parameters. Dynamic queries are also useful for uncommon queries, or prototyping.
Because JPQL is a string based language, dynamic queries using JPQL typically involve
string concatenation. Some JPA providers provide more dynamic query languages, and in
JPA 2.0 a Criteria API will be provided to make dynamic queries easier.
Dynamic queries can use parameters, and query hints the same as named queries.
Common Queries
or,
Advanced
Flush Mode
Within a transaction context in JPA, changes made to the managed objects are normally not
flushed (written) to the database until commit. So if a query were executed against the
database directly, it would not see the changes made within the transaction, as these
changes are only made in memory within the Java. This can cause issues if new objects have
been persisted, or objects have been removed or changed, as the application may expect
the query to return these results. Because of this JPA requires that the JPA provider
performs a flush of all changes to the database before any query operation. This however
can cause issues if the application is not expecting that a flush as a side effect of a query
operation. If the application changes are not yet in a state to be flushed, a flush may not be
desired. Flushing also can be expensive and causes the database transaction, and database
locks are other resources to be held for the duration of the transaction, which can effect
performance and concurrency.
JPA allows the flush mode for a query to be configured using the FlushModeType (https:/ /
java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ FlushModeType. html) enum and the
Query.setFlushMode() (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/
Query. html#setFlushMode(javax. persistence. FlushModeType)) API. The flush mode is
either AUTO the default which means flush before every query execution, or COMMIT which
means only flush on commit. The flush mode can also be set on an EntityManager using
the EntityManager.setFlushMode() (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ EntityManager. html#setFlushMode(javax. persistence. FlushModeType)) API,
to affect all queries executed with the EntityManager. The EntityManager.flush()
(https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ EntityManager.
html#flush()) API can be called directly on the EntityManager anytime that a flush is
desired.
Some JPA providers also let the flush mode be configured through persistence unit
properties, or offer alternatives to flushing, such as performing the query against the in
memory objects.
Java Persistence/ Print version 115
Stored Procedures
A stored procedure is a database-defined procedure typically written in a proprietary
database language, such as PL/SQL in Oracle.
JPQL BNF
The following defines the structure of the JPQL query language. For further examples and
usage see Querying.
| = or
[] = optional
* = repeatable
{} = optional
Select
Select employee from Employee employee join employee.address address
where address.city = :city and employee.firstName like :name order by
employee.firstName
From
FROM Employee employee JOIN FETCH employee.address LEFT OUTER JOIN
FETCH employee.phones JOIN employee.manager manager, Employee ceo
Select Clause
SELECT employee.id, employee.phones
Where
WHERE employee.firstName = :name AND employee.address.city LIKE 'Ott%'
ESCAPE '/' OR employee.id IN (1, 2, 3) AND (employee.salary * 2) > 40000
Functions
LENGTH(SUBSTRING(UPPER(CONCAT('FOO', :bar)), 1, 5))
Group By
GROUP BY employee.address.country, employee.address.city HAVING
COUNT(employee.id) > 500
Order By
ORDER BY employee.address.country, employee.address.city DESC
Subquery
WHERE employee.salary = (SELECT MAX(wellPaid.salary) FROM Employee
wellPaid)
Update
UPDATE Employee SET salary = salary * 2 WHERE address.city = :city
Delete
DELETE FROM Employee WHERE address.city = :city
Persisting
JPA uses the EntityManager (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ EntityManager. html) API for runtime usage. The EntityManager represents
the application session or dialog with the database. Each request, or each client will use its
own EntityManager to access the database. The EntityManager also represents a
transaction context, and in a typical stateless model an new EntityManager is created for
each transaction. In a stateful model, and EntityManager may match the lifecycle of a
client's session.
The EntityManager provides API for all required persistence operations. These includes
CRUD operations including:
• persist (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ EntityManager.
html#persist(java. lang. Object)) (INSERT)
• merge (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ EntityManager.
html#merge(java. lang. Object)) (UPDATE)
• remove (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ EntityManager.
html#remove(java. lang. Object)) (DELETE)
• find (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/ persistence/ EntityManager.
html#find(java. lang. Class,java. lang. Object)) (SELECT)
The EntityManager is an object-oriented API, so does not map directly onto database SQL
or DML operations. For example to update an object, you just need to read the object and
change its state through its set methods, and then call commit on the transaction. The
EntityManager figures out which objects you changed and performs the correct updates to
the database, there is no explicit update operation in JPA.
Persist
The EntityManager.persist() (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ EntityManager. html#persist(java. lang. Object)) operation is used to insert a
new object into the database. persist does not directly insert the object into the database,
it just registers it as new in the persistence context (transaction). When the transaction is
committed, or if the persistence context is flushed, then the object will be inserted into the
database.
If the object uses a generated Id, the Id will normally be assigned to the object when
persist is called, so persist can also be used to have an object's Id assigned. The one
exception is if IDENTITY sequencing is used, in this case the Id is only assigned on commit
or flush because the database will only assign the Id on INSERT. If the object does not use
a generated Id, you should normally assign its Id before calling persist.
The persist operation can only be called within a transaction, an exception will be thrown
outside of a transaction. The persist operation is in-place, in that the object being
persisted will become part of the persistence context. The state of the object at the point of
Java Persistence/ Print version 122
the commit of the transaction will be persisted, not its state at the point of the persist
call.
persist should normally only be called on new objects. It is allowed to be called on existing
objects if they are part of the persistence context, this is only for the purpose of cascading
persist to any possible related new objects. If persist is called on an existing object that is
not part of the persistence context, then an exception may be thrown, or it may be
attempted to be inserted and a database constraint error may occur, or if no constraints are
defined, it may be possible to have duplicate data inserted.
persist can only be called on Entity objects, not on Embeddable objects, or collections, or
non-persistent objects. Embeddable objects are automatically persisted as part of their
owning Entity.
Calling persist is not always required. If you related a new object to an existing object
that is part of the persistence context, and the relationship is cascade persist, then it will be
automatically inserted when the transaction is committed, or when the persistence context
is flushed.
Example persist
EntityManager em = getEntityManager();
em.getTransaction().begin();
em.persist(employee);
em.getTransaction().commit();
Cascading Persist
Calling persist on an object will also cascade the persist operation to across any
relationship that is marked as cascade persist. If a relationship is not cascade persist, and a
related object is new, then an exception may be thrown if you do not first call persist on
the related object. Intuitively you may consider marking every relationship as cascade
persist to avoid having to worry about calling persist on every objects, but this can also lead
to issues.
One issue with marking all relationships cascade persist is performance. On each persist
call all of the related objects will need to be traversed and checked if they reference any
new objects. This can actually lead to n^2 performance issues if you mark all relationships
cascade persist, and persist a large new graph of objects. If you just call persist on the
root object, this is ok. However, if you call persist on each object in the graph, then you
will traverse the entire graph for each object in the graph, and this can lead to a major
performance issue. The JPA spec should probably define persist to only apply to new
objects, not already part of the persistence context, but it requires persist apply to all
objects, whether new, existing, or already persisted, so can have this issue.
Java Persistence/ Print version 123
A second issue is that if you remove an object to have it deleted, if you then call persist
on the object, it will resurrect the object, and it will become persistent again. This may be
desired if it is intentional, but the JPA spec also requires this behavior for cascade persist.
So if you remove an object, but forget to remove a reference to it from a cascade persist
relationship, the remove will be ignored.
I would recommend only marking relationships that are composite or privately owned as
cascade persist.
Merge
The EntityManager.merge() (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ EntityManager. html#merge(java. lang. Object)) operation is used to merge
the changes made to a detached object into the persistence context. merge does not
directly update the object into the database, it merges the changes into the persistence
context (transaction). When the transaction is committed, or if the persistence context is
flushed, then the object will be updated in the database.
Normally merge is not required, although it is frequently misused. To update an object you
simply need to read it, then change its state through its set methods, then commit the
transaction. The EntityManager will figure out everything that has been changed and
update the database. merge is only required when you have a detached copy of a
persistence object. A detached object is one that was read through a different
EntityManager (or in a different transaction in a JEE managed EntityManager), or one that
was cloned, or serialized. A common case is a stateless SessionBean where the object is
read in one transaction, then updated in another transaction. Since the update is processed
in a different transaction, with a different EntityManager, it must first be merged. The
merge operation will look-up/find the managed object for the detached object, and copy
each of the detached objects attributes that changed into the managed object, as well as
cascading any related objects marked as cascade merge.
The merge operation can only be called within a transaction, an exception will be thrown
outside of a transaction. The merge operation is not in-place, in that the object being
merged will never become part of the persistence context. Any further changes must be
made to the managed object returned by the merge, not the detached object.
merge is normally called on existing objects, but can also be called on new objects. If the
object is new, a new copy of the object will be made and registered with the persistence
context, the detached object will not be persisted itself.
merge can only be called on Entity objects, not on Embeddable objects, or collections, or
non-persistent objects. Embeddable objects are automatically merged as part of their
owning Entity.
Example merge
EntityManager em = createEntityManager();
Employee detached = em.find(Employee.class, id);
em.close();
...
em = createEntityManager();
em.getTransaction().begin();
Employee managed = em.merge(detached);
Java Persistence/ Print version 124
em.getTransaction().commit();
Cascading Merge
Calling merge on an object will also cascade the merge operation across any relationship
that is marked as cascade merge. Even if the relationship is not cascade merge, the
reference will still be merged. If the relationship is cascade merge the relationship and
each related object will be merged. Intuitively you may consider marking every relationship
as cascade merge to avoid having to worry about calling merge on every objects, but this is
normally a bad idea.
One issue with marking all relationships cascade merge is performance. If you have an
object with a lot of relationships, the each merge call can require to traverse a large graph
of objects.
Another issues is that your detached object is corrupt in one way or another. By this I mean
you have, for example, an Employee who has a manager, but that manager has a different
copy of the detached Employee object as its managedEmployee. This may cause the same
object to be merged twice, or at least may not be consistent which object will be merged, so
you may not get the changes you expect merged. The same is true if you didn't change an
object at all, but some other user did, if merge cascades to this unchanged object, it will
revert the other user's changes, or throw an OptimisticLockException (depending on
your locking policy). This is normally not desirable.
I would recommend only marking relationships that are composite or privately owned as
cascade merge.
Transient Variables
Another issue with merge is transient variables. Since merge is normally used with object
serialization, if a relationship was marked as transient (Java transient, not JPA transient),
then the detached object will contain null, and null will be merged into the object, even
though it is not desired. This will occur even if the relationship was not cascade merge, as
merge always merges the references to related objects. Normally transient is required when
using serialization to avoid serializing the entire database when only a single, or small set
of objects are required.
One solution is to avoid marking anything transient, and instead use LAZY relationships is
JPA to limit what is serialized (lazy relationships that have not been accessed, will normally
not be serialized). Another solution is to manually merge in your own code.
Some JPA provides provide extended merge operations, such as allowing a shallow merge
or deep merge, or merging without merging references.
Remove
The EntityManager.remove() (https:/ / java. sun. com/ javaee/ 5/ docs/ api/ javax/
persistence/ EntityManager. html#remove(java. lang. Object)) operation is used to delete
an object from the database. remove does not directly delete the object from the database,
it marks the object to be deleted in the persistence context (transaction). When the
transaction is committed, or if the persistence context is flushed, then the object will be
deleted from the database.
Java Persistence/ Print version 125
The remove operation can only be called within a transaction, an exception will be thrown
outside of a transaction. The remove operation must be called on a managed object, not on
a detached object. Generally you must first find the object before removing it, although it
is possible to call EntityManager.getReference() on the object's Id and call remove on
the reference. Depending on how you JPA provider optimizes getReference and remove, it
may not require reading the object from the database.
remove can only be called on Entity objects, not on Embeddable objects, or collections, or
non-persistent objects. Embeddable objects are automatically removed as part of their
owning Entity.
Example merge
EntityManager em = getEntityManager();
em.getTransaction().begin();
Employee employee = em.find(Employee.class, id);
em.remove(employee);
em.getTransaction().commit();
Cascading Remove
Calling remove on an object will also cascade the remove operation across any relationship
that is marked as cascade remove.
Note that cascade remove only effects the remove call. If you have a relationship that is
cascade remove, and remove an object from the collection, or dereference an object, it will
not be removed. You must explicitly call remove on the object to have it deleted. Some JPA
providers provide an extension to provide this behavior, and in JPA 2.0 there will be an
orphanRemoval option on OneToMany and OneToOne mappings to provide this.
Reincarnation
Normally an object that has been removed, stays removed, but in some cases you may need
to bring the object back to life. This normally occurs with natural ids, not generated ones,
where a new object would always get an new id. Generally the desire to reincarnate an
object occurs from a bad object model design, normally the desire to change the class type
of an object (which cannot be done in Java, so a new object must be created). Normally the
best solution is to change your object model to have your object hold a type object which
defines its type, instead of using inheritance. But sometimes reincarnation is desirable.
When done it two separate transactions, this is normally fine, first you remove the object,
then you persist it back. This can be more complex if you wish to remove and persist an
object with the same Id in the same transaction. If you call remove on an object, then call
persist on the same object, it will simply no longer be removed. If you call remove on an
object, then call persist on a different object with the same Id the behavior may depend
on your JPA provider, and probably will not work. If you call flush after calling remove,
then call persist, then the object should be successfully reincarnated. Note that it will be a
different row, the existing row will have been deleted, and a new row inserted. If you wish
the same row to be updated, you may need to resort to using a native SQL update query.
Java Persistence/ Print version 126
Advanced
Get Reference
Clear
Get Delegate
A transaction is a set of operations that either fail or succeed as a unit. Transactions are a
fundamental part of persistence. A database transaction consists of a set of SQL DML (Data
Manipulation Language) operations that are committed or rolled back as a single unit. An
object level transaction is one in which a set of changes made to a set of objects are
committed to the database as a single unit.
JPA provides two mechanisms for transactions. When used in JEE JPA provides integration
with JTA (Java Transaction API). JPA also provides its own Transaction implementation for
JSE and for use in a non-managed mode in JEE. Transactions in JPA are always at the object
level, this means that all changes made to all persistent objects in the persistence context
are part of the transaction.
Caching
Caching is the most important performance optimization technique. There are many things
that can be cached in persistence, objects, data, database connections, database
statements, query results, meta-data, relationships, to name a few. Caching in object
persistence normally refers to the caching of objects or their data. Caching also influences
object identity, that is that if you read an object, then read the same object again you
should get the identical object back (same reference).
JPA does not define a server object cache, JPA providers can support a server object cache
or not, however most do. Caching in JPA is required with-in a transaction or within an
extended persistence context to preserve object identity, but JPA does not require that
caching be supported across transactions or persistence contexts.
There are two types of object caching. You can cache the objects themselves including all of
their structure and relationships, or you can cache their database row data. Both provide a
benefit, however just caching the row data is missing a huge part of the caching benefit as
the retrieval of each relationship typically involves a database query, and the bulk of the
cost of reading an object is spent in retrieving its relationships.
Java Persistence/ Print version 127
Data Cache
Object Identity
Stale Data
Refreshing
Caching in a Cluster
Databases
MySQL
Using MySQL with Java Persistence API is quite straightforward as the JDBC driver is
available directly from MySQL web site (http:/ / dev. mysql. com/ ).
MySQL Connector/J is the official JDBC driver for MySQL and has a good documentation
available directly on the web site.
In this page we will see some aspects of managing MySQL using the Persistence API.
Installing
Installation is straightforward and consists in making the .jar file downloaded from MySQL
web site visible to the JVM. It can be already installed if you are using Apache or JBOSS.
Configuration tips
You can learn a lot from the documentation on MySQL web site (http:/ / dev. mysql. com/
doc/ refman/ 5. 0/ en/ connector-j-reference-configuration-properties. html).
in the property.xml, you will be likely need to create a new database. To create the
database "NewDB" automatically, you need to give the following URL to the jdbc
connection:
<property name="toplink.jdbc.url"
value="jdbc:mysql://localhost:3306/NewDB?createDatabaseIfNotExist=true"/>
If not, the persistence API will complain that the database does not exist.
Java Persistence/ Print version 128
References
Resources Wikis
• EJB 3.0 JPA 1.0 Spec (http:/ / jcp. org/ aboutJava/ • EclipseLink Wiki (http:/ / wiki. eclipse. org/
communityprocess/ final/ jsr220/ index. html) EclipseLink)
• JPA 2.0 Spec (http:/ / jcp. org/ en/ jsr/ • Oracle TopLink Wiki (http:/ / wiki. oracle. com/ page/
detail?id=317) TopLink)
• JPA 1.0 ORM XML Schema (http:/ / java. sun. com/ • Glassfish TopLink Essentials Wiki (http:/ / wiki.
xml/ ns/ persistence/ orm_1_0. xsd) glassfish. java. net/ Wiki.
• JPA 1.0 Persistence XML Schema (http:/ / java. sun. jsp?page=TopLinkEssentials)
com/ xml/ ns/ persistence/ persistence_1_0. xsd) • Hibernate Wiki (http:/ / www. hibernate. org/ 37.
• JPA 1.0 JavaDoc (https:/ / java. sun. com/ javaee/ 5/ html)
docs/ api/ javax/ persistence/ package-summary. • JPA on Wikipedia (http:/ / en. wikipedia. org/ wiki/
html) Java_Persistence_API)
• JPQL BNF • JPA on Javapedia (http:/ / wiki. java. net/ bin/ view/
• JPA 2.0 Reference Implementation Development Javapedia/ JPA)
(http:/ / wiki. eclipse. org/ EclipseLink/ • JPA on freebase (http:/ / www. freebase. com/ view/
Development/ JPA) guid/ 9202a8c04000641f8000000004666d33)
• Java Programming • JPA on DMOZ (Open Directory) (http:/ / www. dmoz.
org/ Computers/ Programming/ Languages/ Java/
Databases_and_Persistence/ Object_Persistence/ JPA/
)
Forums Products
• Sun EJB Forum (http:/ / forum. java. sun. com/ • Oracle TopLink Home (http:/ / www. oracle. com/
forum. jspa?forumID=13) technology/ products/ ias/ toplink/ index. html)
• JavaRanch ORM Forum (http:/ / saloon. javaranch. • EclipseLink Home (http:/ / www. eclipse. org/
com/ cgi-bin/ ubb/ ultimatebb. cgi?ubb=forum& eclipselink/ )
f=78) • TopLink Essentials Home (https:/ / glassfish. dev. java.
• Nabble JPA Forum (http:/ / www. nabble. com/ net/ javaee5/ persistence/ )
JPA-f27109. html) • Hibernate Home (http:/ / www. hibernate. org/ )
• EclipseLink Forum (http:/ / www. nabble. com/ • Open JPA Home (http:/ / openjpa. apache. org/ )
EclipseLink-f26430. html) • HiberObjects (http:/ / objectgeneration. com/ eclipse/ )
• EclipseLink Newsgroup (http:/ / www. eclipse. org/
newsportal/ thread. php?group=eclipse. rt.
eclipselink)
• Oracle TopLink Forum (http:/ / forums. oracle. com/
forums/ forum. jspa?forumID=48)
• Hibernate Forum (http:/ / forum. hibernate. org/ )
• TopLink Essentials Mailing List (Glassfish
persistence) (http:/ / www. nabble. com/ java.
net---glassfish-persistence-f13455. html)
Java Persistence/ Print version 129
Blogs Books
• Java Persistence (http:/ / java-persistence. blogspot. • Pro EJB 3 (http:/ / www. amazon. com/ gp/ product/
com/ ) (Doug Clarke) 1590596455/ 102-2412923-9620152?v=glance&
• System.out (http:/ / jroller. com/ mkeith/ ) (Mike n=283155)
Keith)
• On TopLink (http:/ / ontoplink. blogspot. com/ )
(Shaun Smith)
• EclipseLink (http:/ / eclipselink. blogspot. com/ )
• Hibernate Blog (http:/ / blog. hibernate. org/ )
Article Sources and Contributors 130
License
Creative Commons Attribution-Share Alike 3.0 Unported
http:/ / creativecommons. org/ licenses/ by-sa/ 3. 0/