The document provides an overview of getting started with the Java Persistence API (JPA). It discusses mapping Java objects to database tables using JPA annotations, obtaining and using an EntityManager to perform CRUD operations, configuring and executing queries, and managing transactions. The key aspects covered are mapping entities and relationships, the EntityManager API, query types (dynamic and named queries), and using container-managed and resource-local transactions.
1. Subscribe Now for FREE! refcardz.com
tech facts at your fingertips
CONTENTS INCLUDE:
n
Getting Started With JPA
Getting Started with JPA
n
Mapping an Object
n
Obtaining and Using an Entity Manager
n
Transactions
n
Querying
n
Hot Tips and more... By Mike Keith
Listing 1 – Pet entity class
GETTING STarTED WITh JPa
@Entity
@Table(name=quot;PET_INFOquot;)
The Java Persistence API (JPA) is the Java standard for mapping public class Pet {
Java objects to a relational database. Even though proprietary @Id
mapping products like Hibernate and TopLink still exist, they @Column(name=quot;IDquot;)
are now focused on providing their functionality through int licenseNumber;
String name;
the JPA API, allowing all applications to be portable across
PetType type;
JPA implementations. This refcard will give users enough @ManyToOne
to understand the basics of JPA and get started writing JPA @JoinColumn(name=quot;OWNER_IDquot;)
applications. It covers entities, identifiers, O-R mappings, Owner owner;
using an entity manager, creating and executing queries, and ...
configuration of the persistence.xml file. }
Listing 2 - Owner entity class
@Entity
MaPPING aN ObJECT
public class Owner {
@Id
The basic unit of persistence in JPA is the entity, which is
www.dzone.com
int id;
nothing more than a regular Java class with metadata to String name;
describe how its state maps to the database tables. Metadata @Column(name=quot;PHONE_NUMquot;)
may be in the form of annotations on the entity class itself, or it String phoneNumber;
may be an accompanying XML file, but we are using annotations @OneToOne
Address address;
since they are easier to specify and understand.
@OneToMany(mappedBy=quot;ownerquot;)
List<Pet> pets;
...
Hot When used together, XML mappings can over- }
Tip ride the values specified in annotations
In a bidirectional relationship pair, such as the @OneToMany
relationship in Owner to Pet and the @ManyToOne relationship
Every entity class should have an @Entity marker and an back from Pet to Owner, only one foreign key is required in one
identifier field, indicated by @Id, that is mapped to the primary of the tables to manage both sides of the relationship. As a
key column in the database. When a field contains simple
general rule, the side that does not have the foreign key in it
data and maps to a regular column in the database we call it a
specifies a mappedBy attribute in the relationship annotation and
basic mapping, thus an identifier field is a special kind of basic
specifies the field in the related entity that maps the foreign key.
mapping. When an entity has a field that references one or more
→
other entities, that field maps to a foreign key column, and is
Getting Started with JPa
called a relationship field. Other than the identifier field, basic
mappings do not need to be annotated, but relationships must Get More Refcardz
be specified by their relationship cardinality. (They’re free!)
Defaulting rules in JPA mean that you are not required to specify
n Authoritative content
table names and column names that an entity is mapped to. If
you are not happy with the JPA-assigned defaults then you can
n Designed for developers
always override them through the use of additional mapping n Written by top experts
metadata. For example, by putting @Table on the entity class n Latest tools & technologies
you can make the table name explicit, and by annotating a n Hot tips & examples
basic mapping field with @Column you can define the particular n Bonus content online
column that maps the state in that field. Likewise @JoinColumn n New issue every 1-2 weeks
is used to override the name of the foreign key column for
relationship references. Subscribe Now for FREE!
An example of two mapped entities are the Pet and Owner Refcardz.com
classes shown in Listings 1 and 2.
DZone, Inc. | www.dzone.com
2. 2
Getting Started with JPa
tech facts at your fingertips
Mapping an Object, continued
USING aN ENTITy MaNaGEr
The possible mapping annotations that can be used are:
@Basic @Enumerated @ManyToOne @Temporal The basic purpose of an entity manager is to perform create/
@Embedded @Lob @OneToMany @Transient read/update/delete (CRUD) operations on entities. Listing 5
@EmbeddedId @ManyToMany @OneToOne shows methods that perform these operations.
Listing 5 – Invoking the entity manager
Annotations used to override the names of the tables or
public Pet createPet(int idNum, String name, PetType
columns in the database are:
type) {
@AttributeOverride(s) @PrimaryKeyJoinColumn(s) Pet pet = new Pet(idNum, name, type);
@AssociationOverride(s) @SecondaryTable(s) em.persist(pet);
@Column @SequenceGenerator return pet;
@DiscriminatorColumn @Table }
@JoinColumn(s) @TableGenerator public Pet findPet(int id) {
@JoinTable return em.find(Pet.class, id);
}
Other annotations used to indicate the type of the class or public Pet changeName(int id, String newName) {
other aspects of the model are: Pet pet = this.findPet(id);
pet.setName(newName);
@Entity @IdClass @MappedSuperclass return pet;
@Embeddable @Inheritance @OrderBy }
@GeneratedValue @DiscriminatorValue @Version public void deletePet(int id) {
@Id @MapKey Pet pet = this.findPet(id);
em.remove(pet);
}
ObTaINING aN ENTITy MaNaGEr Note that finding the pet is the first step to being able to
perform update and delete operations on it. Also, an update
The EntityManager class is the main API in JPA. It is used does not even involve invoking the entity manager, but requires
to create new entities, manufacture queries to return sets reading the pet, loading it into the entity manager and then
of existing entities, merge in the state of remotely modified modifying it. The modification will be reflected in the database
entities, delete entities from the database, and more. when the transaction is committed.
There are, generally speaking, two main kinds of entity
managers:
The merge() method can also be used to create
container-managed The managed entity managers may only be obtained Hot entities, but is most useful for merging in entity
within a container that supports the JPA Service Tip
Provider Interface (SPI). changes made on the client side.
non-managed Non-managed entity managers may be obtained
in any environment where a JPA provider is on the
classpath. Listing 3 shows an example of obtaining
a non-managed entity manager by first obtaining TraNSaCTIONS
an EntityManagerFactory instance from the
Persistence root class.
Since we just mentioned transactions, but didn’t explain them,
Listing 3 – Obtaining a non-managed entity manager now would be a good time to state that JPA supports two
different kinds of transactions.
import javax.persistence.*;
... JTA container transactions Used when running in container mode
EntityManagerFactory emf = Persistence resource local transactions Typically used when running in non-container
.createEntityManagerFactory(quot;PetShopquot;); mode.
EntityManager em = emf.createEntityManager();
... JTA transactions are started and committed using the usual
em.close(); container techniques, either calling the UserTransaction API
or making use of container-managed transaction demarcation
In Listing 4 we see how a standard host container can provide a
in EJB or Spring. For example, if the methods in Listing 5 were
simpler way to obtain an entity manager. The only catch is that
in a session bean that had a Required transaction attribute
this is only supported within standard Java EE components (or
containers that are compliant to the JPA container contract), so setting then a transaction would be started at the beginning and
committed at the end of each client method invocation.
this example uses a stateless session bean.
When using local transactions the transaction must be
Listing 4 – Injecting a managed entity manager
demarcated manually by invoking on the EntityTransaction
@Stateless
instance accessed from the entity manager. Each of the three
public class MyBean implements MyInterface {
@PersistenceContext(unitName=quot;PetShopquot;)
methods in Listing 5 that caused the database to change would
EntityManager em; need to have begin and commit calls, as shown in Listing 6 for
... the persist method. Methods that only read from the database
} do not need to occur within a transaction.
DZone, Inc. | www.dzone.com
3. 3
Getting Started with JPa
tech facts at your fingertips
Transactions, continued Querying, continued
Listing 6 – Using EntityTransaction configuration method calls may be made on the query instance
public Pet createPet(int idNum, String name, PetType to configure it. Listing 7 shows an example of creating and
type) { executing a query that returns all the instances of Pet, or the
em.getTransaction().begin(); first 100 if there are more than 100 instances.
Pet pet = new Pet(idNum, name, type);
em.persist(pet); Listing 7 – Creating and executing a dynamic query
em.getTransaction().commit();
return pet; Query q = em.createQuery(quot;SELECT p FROM Pet pquot;);
} q.setMaxResults(100);
List results = q.getResultList();
The complete EntityManager API is listed in Table 1, with a A named query is a query that is defined statically and then
brief description of what each method does. instantiated and executed at runtime. It can be defined as an
Method Description annotation on the entity class, and assigned a name that is
used when the query is created. Listing 8 shows a named query
void persist(Object entity) Persist an entity
defined on the Pet entity.
<T> T merge(T entity); Merge the state of an entity into the
database Listing 8 – Defining a named query
void remove(Object entity); Remove an entity from the database
@NamedQuery(name=quot;Pet.findByNamequot;,
<T> T find( Find and return an instance of an entity class query=quot;SELECT p FROM Pet p WHERE p.name LIKE :pnamequot;)
Class<T> entityClass, @Entity
Object primaryKey);
public class Pet {
<T> T getReference( Create a holder for the primary key of an ...
Class<T> entityClass, entity
}
Object primaryKey);
void flush(); Cause all changes to be written out to the The last identifier is prefixed with a colon (:) character to indicate
database
that it is a named parameter that must be bound at runtime
void setFlushMode( Set the flushing mode for query execution before the query can be executed. Listing 9 shows a method
FlushModeType flushMode);
that executes the query by first instantiating a Query object
FlushModeType getFlushMode(); Get the flushing mode for query execution
using the createNamedQuery() factory method, then binding
void lock( Lock an object to obtain greater isolation
Object entity, consistency guarantees
the pname named parameter to the name that was passed
LockModeType lockMode); into the method, and finally executing the query by invoking
void refresh(Object entity); Update the in-memory entity with the state getResultList().
from the database
Listing 9 – Executing a named query
void clear(); Make all managed entities become
unmanaged public List findAllPetsByName(String petName) {
boolean contains( Determine if an entity is managed Query q = em.createNamedQuery(quot;Pet.findByNamequot;);
Object entity); q.setParameter(quot;pnamequot;, petName);
Query createQuery( Create a dynamic query from JP QL return q.getResultList();
String JP QLString); }
Query createNamedQuery( Create a named query
String name);
Named queries are not only more efficient than
Query createNativeQuery( Create a query from SQL Hot dynamic queries but are also safer since they
String sqlString);
Tip
Query createNativeQuery( Create a query from SQL that returns a given will often get pre-compiled by the persistence
String sqlString,
Class entityClass);
entity type implementation at deployment time
Query createNativeQuery( Create a query from SQL that uses a given
String sqlString, defined mapping The entire Query API is shown in Table 2.
String resultSetMapping);
void joinTransaction(); Join an existing JTA transaction
Query Method Description
List getResultList(); Execute the query and return the results
Object getDelegate(); Access the underlying EntityManager
as a List
implementation
Object getSingleResult(); Execute a query that returns a single result
void close(); Close the EntityManager
int executeUpdate(); Execute an update or delete statement
boolean isOpen(); Determine whether the EntityManager has
been closed Query setMaxResults( Set the maximum number of results to
int maxResult); retrieve
EntityTransaction Access the EntityManager local transaction
getTransaction(); Query setFirstResult( Set the position of the first result to
int startPosition); retrieve
Table 1. EntityManager method summary Query setHint( Set an implementation-specific query hint
String hintName,
Object value);
QUEryING Query setParameter(
String name,
Bind an argument to a named parameter
Object value);
Query setParameter( Bind an instance of java.util.Date to a
Dynamic queries are objects that are created from an entity String name, named parameter
manager, and then executed. The query criteria are specified Date value,
TemporalType temporalType);
at creation time as a Java Persistence Query Language (JP
QL) string. Before executing the query a number of possible Table 2. Query method summary
DZone, Inc. | www.dzone.com
4. 4
Getting Started with JPa
tech facts at your fingertips
Querying, continued Java Persistence Query Language, continued
Query Method Description Clause/Term Syntax
Query setParameter( Bind an instance of java.util.Calendar to a
select_clause SELECT [DISTINCT] select_exp {,select_exp}*
String name, named parameter
Calendar value,
TemporalType temporalType); select_exp variable | state_field_exp | single_rel_exp | aggregate_exp |
constructor_exp
Query setParameter( Bind a parameter by position
int position, aggregate_exp {{AVG | MAX | MIN | SUM} ( [DISTINCT] state_field_exp )} |
Object value); COUNT ( [DISTINCT] variable | state_field_exp | single_rel_
Query setParameter( Bind an instance of java.util.Date to a exp )
int position, positional parameter
Date value, TemporalType constructor_exp NEW constructor_method ( constructor_item {,constructor_
temporalType); item}* )
Query setParameter( Bind an instance of java.util.Calendar to a constructor_item single_rel_exp | aggregate_exp
int position, positional parameter
Calendar value, TemporalType
from_clause FROM variable_decl {, {variable_decl | in_decl}}*
temporalType);
Query setFlushMode( Set the flush mode for the query variable_decl entityName [AS] variable {join_exp | fetch_join_exp}*
FlushModeType flushMode);
join_exp [LEFT [OUTER] | INNER] JOIN rel_field [AS] variable
Table 2. Query method summary, continued fetch_join_exp [LEFT [OUTER] | INNER] JOIN FETCH rel_field
in_decl IN ( multi_rel_exp ) [AS] variable
Java PErSISTENCE QUEry LaNGUaGE
where_clause WHERE conditional_exp
The Java Persistence Query Language is SQL-like, but operates conditional_exp {[NOT] conditional} | {conditional_exp {AND | OR}
over the entities and their mapped persistent attributes instead conditional_exp}
of the SQL schema. Many of the SQL functions and even conditional comparison | between_exp | like_exp | in_exp | compare_
null_exp | compare_empty_exp | compare_member_exp |
reserved words are supported in JP QL. exists_exp
There are three basic types of JP QL statements, of which the comparison compare_string | compare_boolean | compare_enum |
compare_datetime | compare_entity | compare_arithmetic
first is monstrously the most popular and useful: selects, bulk
compare_string string_exp {= | > | >= | < | <= | <>} {string_exp | all_any_
updates and bulk deletes. subquery}
1. select_clause from_clause [where_clause] [groupby_clause] compare_boolean boolean_exp {= | <>} {boolean_exp | all_any_subquery}
[having_clause] [orderby_clause] compare_enum enum_exp {= | <>} {enum_exp | all_any_subquery}
2. update_clause [where_clause]
compare_datetime datetime_exp {= | > | >= | < | <= | <>} {datetime_exp |
3. delete_clause [where_clause] all_any_subquery}
compare_entity entity_exp {= | <>} {entity_exp | all_any_subquery}
Bulk deletes are useful for doing test clean-up compare_arithmetic arithmetic_exp {= | > | >= | < | <= | <>} {arithmetic_exp |
Hot and clearing all of the data from the entity tables
all_any_subquery}
Tip all_any_subquery {ALL | ANY | SOME} ( subquery )
without having to revert to SQL.
between_exp arithmetic_exp [NOT] BETWEEN arithmetic_exp AND
arithmetic_exp
A simplified table of most of the supported syntax is in
like_exp string_exp [NOT] LIKE pattern_value [ESCAPE escape_char]
Table 4. For complete and precise grammar, consult the JPA
in_exp state_field_exp [NOT] IN ( {literal | input_param} {,{literal |
specification at http://jcp.org/aboutJava/communityprocess/ input_param}}* )
final/jsr220/index.html. The primitive terms are shown in Table 3. compare_null_exp {single_rel_exp | input_param} IS [NOT] NULL
Term Description compare_empty_exp multi_rel_exp IS [NOT] EMPTY
entityName Name of an entity (which is defaulted to the name of the compare_member_exp entity_exp [NOT] MEMBER [OF] multi_rel_exp
entity class)
exists_exp [NOT] EXISTS ( subquery )
variable Identifier variable following Java identifier rules
state_field_exp Term that resolves to an entity field containing simple arithmetic_exp arithmetic | ( subquery )
state (e.g. if Pet is represented by variable p, then p.name
or p.owner.phoneNumber) string_exp string | ( subquery )
single_rel_exp Term that resolves to an entity field containing an one-to- entity_exp variable | input_param | single_rel_exp
one or many-to-one relationship (e.g. if Pet is represented
by variable p, then p.owner or p.owner.address) enum_exp enum | ( subquery )
multi_rel_exp Term that resolves to an entity field containing a one- datetime_ exp datetime | ( subquery )
to-many or many-to-many relationship (e.g. if Owner is
represented by variable o, then o.pets) boolean_exp boolean | ( subquery )
rel_field Term composed of a variable and one of its relationship
fields, with no traversing of intermediate relationships arithmetic arithmetic_term | {arithmetic { * | / | + | - } arithmetic}
(e.g. if Pet is represented by variable p, then p.owner)
arithmetic_term state_field_exp | literal | input_param | aggregate_exp |
constructor_method Constructor for a non-entity class (i.e. the name of the numeric_function | ( arithmetic )
class)
string state_field_exp | literal | input_param | aggregate_exp |
input_param Variable that represents an input parameter and must be string_function
bound before the query can be executed
literal A value of a particular type such as a string or integer (e.g. enum state_field_exp | literal | input_param
‘Iggy Pop’, or 42)
datetime state_field_exp | input_param | aggregate_exp | datetime_
pattern_value A valid SQL pattern string (e.g. “% Smith”) function
escape_char A character to be escaped boolean state_field_exp | literal | input_param
Table 3. Primitive terms for JP QL grammar Table 4. Simplified JP QL Grammar
DZone, Inc. | www.dzone.com
5. 5
Getting Started with JPa
tech facts at your fingertips
Java Persistence Query Language, continued Configuration, continued
Clause/Term Syntax for that configuration unit. In a non-managed environment
string_function CONCAT ( string , string ) |
the target database is typically specified through the use
SUBSTRING ( string , arithmetic , arithmetic) | of vendor-specific properties that describe the JDBC driver
TRIM ( [[{LEADING | TRAILING | BOTH}] [trim_char] FROM] and connection properties to use. Also, in non-managed
string ) |
LOWER ( string ) |
environments the entity classes must be enumerated in class
UPPER ( string ) elements, whereas in managed containers the entity classes
datetime_function CURRENT_DATE | CURRENT_TIME | CURRENT_ will be automatically detected. Examples of container and non-
TIMESTAMP container persistence unit elements are indicated in Listings 10
numeric_function LENGTH ( string ) | and 11, respectively.
LOCATE ( string , string [ , arithmetic] ) |
ABS ( arithmetic ) | Listing 10 – Container persistence unit configuration
SQRT ( arithmetic ) |
MOD ( arithmetic , arithmetic ) |
<persistence-unit name=quot;PetShopquot;>
SIZE ( multi_rel_ exp ) <jta-data-source>jdbc/PetShopDB</jta-data-source>
</persistence-unit>
subquery SELECT [DISTINCT] {variable | single_rel_exp | aggregate_
exp}
FROM subquery_decl {, subquery_decl}* Listing 11 – Non-container persistence unit configuration
[where_clause] <persistence-unit name=quot;PetShopquot;>
subquery_decl variable_decl | {single_rel_exp [AS] variable} | in_decl <class>com.acme.petshop.Pet</class>
...
update_clause UPDATE entityName [[AS] variable] SET update_item <class>com.acme.petshop.Owner</class>
{,{update_item}}*
<properties>
update_item {state_field_exp | single_rel_exp} = new_value
<property name=quot;eclipselink.jdbc.driverquot;
new_value variable | input_param | arithmetic | string | boolean | datetime value=quot;oracle.jdbc.OracleDriverquot;/>
| enum | NULL
<property name=quot;eclipselink.jdbc.urlquot;
delete_clause DELETE FROM entityName [[AS] variable] value=quot;jdbc:oracle:thin:@localhost:1521:XEquot;/>
<property name=quot;eclipselink.jdbc.userquot;
groupby_clause GROUP BY groupby_item {, groupby_item}*
value=quot;scottquot;/>
groupby_item single_rel_exp | variable <property name=quot;eclipselink.jdbc.passwordquot;
value=quot;tigerquot;/>
having_clause HAVING conditional_exp </properties>
</persistence-unit>
orderby_clause ORDER BY orderby_item {, orderby_item}*
orderby_item state_field_exp [ASC | DESC]
A provider implementation will be found by
Table 4. Simplified JP QL Grammar, continued Hot default, so avoid using the provider element and
Tip binding yourself to a specific provider unless
you really are dependent upon that provider.
JP QL queries can return data projections over
Hot entity attributes, averting instantiation of the
Tip A hierarchical view of the possible XML elements in a
actual entity objects persistence.xml file are shown in Figure 1. All of the elements
are optional and the starred elements may be pluralized.
CONfIGUraTION
persistence
*
Without counting the mappings from the entity to the database
tables, there is really only one unit of JPA configuration needed persistence-unit
to get your application up and running. It is based on the • name
• transaction type
notion of a persistence unit, and is configured in a file called
persistence.xml, which must always be placed in the META-
INF directory of your deployment unit. Each persistence unit is provider
a configuration closure over the settings necessary to run in the jta-data-source
relevant environment. The parent element in a persistence.xml
file is the persistence element and may contain one or more non-jta-data-source
persistence-unit elements representing different execution * mapping-file
configurations. Each one must be named using the mandatory
* jar-file
persistence-unit name attribute.
* class
There are slightly different requirements for configuring the
exclude-unlisted-classes * property
persistence unit, depending upon whether you are deploying • name
to a managed container environment or a non-managed one. In properties • value
a managed container the target database is indicated through
the jta-data-source element, which is the JNDI name for the
managed data source describing where the entity state is stored Figure 1. XML elements in persistence.xml file
DZone, Inc. | www.dzone.com