HHH-4933 improve EM doc wrt JPA 2

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18941 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Emmanuel Bernard 2010-03-09 14:50:32 +00:00
parent 9be297241d
commit 5aa0138ec2
4 changed files with 929 additions and 690 deletions

View File

@ -67,7 +67,7 @@
<para>If you use Maven, add the following dependencies</para>
<programlisting>&lt;project ...&gt;
<programlisting role="XML" language="XML">&lt;project ...&gt;
...
&lt;dependencies&gt;
&lt;dependency&gt;
@ -100,7 +100,7 @@
configuration, so by default, your persistence.xml will be quite
minimalist:</para>
<programlisting>&lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"
<programlisting role="XML" language="XML">&lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0"&gt;
@ -116,7 +116,7 @@
<para>Here's a more complete example of a
<filename><literal>persistence.xml</literal></filename> file</para>
<programlisting>&lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"
<programlisting role="XML" language="XML">&lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0"&gt;
@ -211,7 +211,7 @@
environment, the persistence.xml file is not under the same root
directory or jar than your domain model).</para>
<programlisting> &lt;jar-file&gt;file:/home/turin/work/local/lab8/build/classes&lt;/jar-file&gt;</programlisting>
<programlisting role="XML" language="XML"> &lt;jar-file&gt;file:/home/turin/work/local/lab8/build/classes&lt;/jar-file&gt;</programlisting>
</listitem>
</varlistentry>
@ -275,7 +275,7 @@
</listitem>
</itemizedlist>
<para> See Hibernate Annotation's documentation for more
<para>See Hibernate Annotation's documentation for more
details.</para>
</listitem>
</varlistentry>
@ -323,14 +323,14 @@
<literal>&lt;validation-mode&gt;</literal>. To use it, add a
regular property</para>
<programlisting>&lt;property name="javax.persistence.validation.mode"&gt;
<programlisting role="XML" language="XML">&lt;property name="javax.persistence.validation.mode"&gt;
ddl
&lt;/property&gt;</programlisting>
<para>With this approach, you can mix ddl and callback
modes:</para>
<programlisting>&lt;property name="javax.persistence.validation.mode"&gt;
<programlisting role="XML" language="XML">&lt;property name="javax.persistence.validation.mode"&gt;
ddl, callback
&lt;/property&gt;</programlisting>
</listitem>
@ -427,7 +427,7 @@
the version embedded in the hibernate-entitymanager.jar. It won't fetch
the resource from the internet.</para>
<programlisting>&lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"
<programlisting role="XML" language="XML">&lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0"&gt;</programlisting>
@ -441,7 +441,7 @@
<classname>EntityManager</classname>. The bootstrap class is
<classname>javax.persistence.Persistence</classname>, e.g.</para>
<programlisting>EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1");
<programlisting role="JAVA" language="JAVA">EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1");
//or
@ -528,8 +528,6 @@ EntityManagerFactory programmaticEmf =
reference documentation for a complete listing. There are however a
couple of properties available in the EJB3 provider only.</para>
<para></para>
<table>
<title>Hibernate Entity Manager specific properties</title>
@ -665,7 +663,7 @@ EntityManagerFactory programmaticEmf =
<para>Here is a typical configuration in a Java SE environment</para>
<programlisting>&lt;persistence&gt;
<programlisting role="XML" language="XML">&lt;persistence&gt;
&lt;persistence-unit name="manager1" transaction-type="RESOURCE_LOCAL"&gt;
&lt;class&gt;org.hibernate.ejb.test.Cat&lt;/class&gt;
&lt;class&gt;org.hibernate.ejb.test.Distributor&lt;/class&gt;
@ -697,7 +695,7 @@ EntityManagerFactory programmaticEmf =
<para>TODO: me more descriptive on some APIs like setDatasource()</para>
<programlisting>Ejb3Configuration cfg = new Ejb3Configuration();
<programlisting role="JAVA" language="JAVA">Ejb3Configuration cfg = new Ejb3Configuration();
EntityManagerFactory emf =
cfg.addProperties( properties ) //add some properties
.setInterceptor( myInterceptorImpl ) // set an interceptor
@ -714,9 +712,9 @@ EntityManagerFactory emf =
<title>Event listeners</title>
<para>Hibernate Entity Manager needs to enhance Hibernate core to
implements all the EJB3 semantics. It does that through the event listener
implements all the JPA semantics. It does that through the event listener
system of Hibernate. Be careful when you use the event system yourself,
you might override some of the EJB3 semantics. A safe way is to add your
you might override some of the JPA semantics. A safe way is to add your
event listeners to the list given below.</para>
<table>
@ -793,15 +791,13 @@ EntityManagerFactory emf =
<row>
<entry>pre-insert</entry>
<entry>org.hibernate.secure.JACCPreInsertEventListener,
org.hibernate.valitator.event.ValidateEventListener</entry>
<entry>org.hibernate.secure.JACCPreInsertEventListener</entry>
</row>
<row>
<entry>pre-insert</entry>
<entry>org.hibernate.secure.JACCPreUpdateEventListener,
org.hibernate.valitator.event.ValidateEventListener</entry>
<entry>org.hibernate.secure.JACCPreUpdateEventListener</entry>
</row>
<row>
@ -861,7 +857,7 @@ EntityManagerFactory emf =
<classname>Persistence</classname> class is bootstrap class to create an
entity manager factory.</para>
<programlisting>// Use persistence.xml configuration
<programlisting role="JAVA" language="JAVA">// Use persistence.xml configuration
EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1")
EntityManager em = emf.createEntityManager(); // Retrieve an application managed entity manager
// Work with the EM
@ -896,4 +892,4 @@ emf.close(); //close at application end</programlisting>
be no performance cost. For more information on Hibernate Validator,
please refer to the Hibernate Annotations reference guide.</para>
</section>
</chapter>
</chapter>

View File

@ -1,4 +1,4 @@
<?xml version='1.0' encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
@ -22,15 +22,15 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="objectstate">
<title>Working with objects</title>
<section>
<title>Entity states</title>
<para>Like in Hibernate (comparable terms in parantheses), an entity
<para>Like in Hibernate (comparable terms in parentheses), an entity
instance is in one of the following states:</para>
<itemizedlist>
@ -63,7 +63,7 @@
<para>The <classname>EntityManager</classname> API allows you to change
the state of an entity, or in other words, to load and store objects. You
will find persistence with EJB3 easier to understand if you think about
will find persistence with JPA easier to understand if you think about
object state management, not managing of SQL statements.</para>
</section>
@ -102,7 +102,8 @@ em.find( Cat.class, new Long(catId) );</programlisting>
<para>In some cases, you don't really want to load the object state, but
just having a reference to it (ie a proxy). You can get this reference
using the <literal>getReference()</literal> method. This is especially
useful to link a child to its parent without having to load the parent.</para>
useful to link a child to its parent without having to load the
parent.</para>
<programlisting>child = new Child();
child.SetName("Henry");
@ -128,32 +129,33 @@ em.refresh(cat); //re-read the state (after the trigger executes)</programlistin
<para>If you don't know the identifier values of the objects you are
looking for, you need a query. The Hibernate EntityManager implementation
supports an easy-to-use but powerful object-oriented query language
(EJB3-QL) which has been inspired by HQL (and vice-versa). Both query
languages are portable across databases, the use entity and property names
as identifiers (instead of table and column names). You may also express
your query in the native SQL of your database, with optional support from
EJB3 for result set conversion into Java business objects.</para>
(JP-QL) which has been inspired by HQL (and vice-versa). HQL is strictly
speaking a superset of JP-QL. Both query languages are portable across
databases, the use entity and property names as identifiers (instead of
table and column names). You may also express your query in the native SQL
of your database, with optional support from JPA for result set conversion
into Java business objects.</para>
<section>
<title>Executing queries</title>
<para>EJB3QL and SQL queries are represented by an instance of
<para>JP-QL and SQL queries are represented by an instance of
<classname>javax.persistence.Query</classname>. This interface offers
methods for parameter binding, result set handling, and for execution of
the query. Queries are always created using the current entity
manager:</para>
<programlisting>List cats = em.createQuery(
<programlisting>List&lt;?&gt; cats = em.createQuery(
"select cat from Cat as cat where cat.birthdate &lt; ?1")
.setParameter(1, date, TemporalType.DATE)
.getResultList();
List mothers = em.createQuery(
List&lt;?&gt; mothers = em.createQuery(
"select mother from Cat as cat join cat.mother as mother where cat.name = ?1")
.setParameter(1, name)
.getResultList();
List kittens = em.createQuery(
List&lt;?&gt; kittens = em.createQuery(
"from Cat as cat where cat.mother = ?1")
.setEntity(1, pk)
.getResultList();
@ -165,17 +167,43 @@ Cat mother = (Cat) em.createQuery(
<para>A query is usually executed by invoking
<methodname>getResultList()</methodname>. This method loads the
resulting instances of the query completly into memory. Entity instances
retrieved by a query are in persistent state. The
resulting instances of the query completely into memory. Entity
instances retrieved by a query are in persistent state. The
<methodname>getSingleResult() </methodname>method offers a shortcut if
you know your query will only return a single object.</para>
<para>JPA 2 provides more type-safe approaches to queries. The truly
type-safe approach is the Criteria API explained in <xref
linkend="querycriteria" />.</para>
<programlisting>CriteriaQuery&lt;Cat&gt; criteria = builder.createQuery( Cat.class );
Root&lt;Cat&gt; cat = criteria.from( Cat.class );
criteria.select( cat );
criteria.where( builder.lt( cat.get( Cat_.birthdate ), catDate ) );
List&lt;Cat&gt; cats = em.createQuery( criteria ).getResultList(); //notice no downcasting is necessary</programlisting>
<para>But you can benefit form some type-safe convenience even when
using JP-QL (note that it's not as type-safe as the compiler has to
trust you with the return type.</para>
<programlisting>//No downcasting since we pass the return type
List&lt;Cat&gt; cats = em.createQuery(
"select cat from Cat as cat where cat.birthdate &lt; ?1", Cat.class)
.setParameter(1, date, TemporalType.DATE)
.getResultList();</programlisting>
<note>
<para>We highly recommend the Criteria API approach. While more
verbose, it provides compiler-enforced safety (including down to
property names) which will pay off when the application will move to
maintenance mode.</para>
</note>
<section>
<title>Projection</title>
<para>An EJB3QL query queries can return tuples of objects if
projection is used. Each result tuple is returned as an object
array:</para>
<para>JPA queries can return tuples of objects if projection is used.
Each result tuple is returned as an object array:</para>
<programlisting>Iterator kittensAndMothers = sess.createQuery(
"select kitten, mother from Cat kitten join kitten.mother mother")
@ -188,6 +216,11 @@ while ( kittensAndMothers.hasNext() ) {
Cat mother = (Cat) tuple[1];
....
}</programlisting>
<note>
<para>The criteria API provides a type-safe approach to projection
results. Check out <xref linkend="querycriteria-tuple" />.</para>
</note>
</section>
<section>
@ -220,9 +253,9 @@ while ( results.hasNext() ) {
<para>Both named and positional query parameters are supported, the
<literal>Query</literal> API offers several methods to bind arguments.
The EJB3 specification numbers positional parameters from one. Named
The JPA specification numbers positional parameters from one. Named
parameters are identifiers of the form <literal>:paramname</literal>
in the query string. Named parameters should be prefered, they are
in the query string. Named parameters should be preferred, they are
more robust and easier to read and understand:</para>
<programlisting>// Named parameter (preferred)
@ -268,13 +301,20 @@ List cats = q.getResultList(); //return cats from the 20th position to 29th</pro
<programlisting>@javax.persistence.NamedQuery(name="eg.DomesticCat.by.name.and.minimum.weight",
query="select cat from eg.DomesticCat as cat where cat.name = ?1 and cat.weight &gt; ?2")</programlisting>
<para>Parameters are bound programatically to the named query, before
<para>Parameters are bound programmatically to the named query, before
it is executed:</para>
<programlisting>Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
q.setString(1, name);
q.setInt(2, minWeight);
List cats = q.getResultList();</programlisting>
List&lt;?&gt; cats = q.getResultList();</programlisting>
<para>You can also use the slightly more type-safe approach:</para>
<programlisting>Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight", Cat.class);
q.setString(1, name);
q.setInt(2, minWeight);
List&lt;Cat&gt; cats = q.getResultList();</programlisting>
<para>Note that the actual program code is independent of the query
language that is used, you may also define native SQL queries in
@ -314,6 +354,29 @@ item = (Item) q.getSingleResult(); //from a class columns names match the mappin
</note>
</section>
<section>
<title>Query lock and flush mode</title>
<para>You can adjust the flush mode used when executing the query as
well as define the lock mode used to load the entities. </para>
<para>Adjusting the flush mode is interesting when one must guaranty
that a query execution will not trigger a flush operation. Most of the
time you don't need to care about this.</para>
<para>Adjusting the lock mode is useful if you need to lock the
objects returns by the query to a certain level.</para>
<programlisting>query.setFlushMode(FlushModeType.COMMIT)
.setLockMode(LockModeType.PESSIMISTIC_READ);</programlisting>
<note>
<para>If you want to use <literal>FlushMode.MANUAL</literal> (ie the
Hibernate specific flush mode), you will need to use a query hint.
See below.</para>
</note>
</section>
<section>
<title>Query hints</title>
@ -395,7 +458,9 @@ item = (Item) q.getSingleResult(); //from a class columns names match the mappin
<row>
<entry>org.hibernate.flushMode</entry>
<entry>Flush mode used for this query</entry>
<entry>Flush mode used for this query (useful to pass
Hibernate specific flush modes, in particular
<literal>MANUAL</literal>).</entry>
</row>
<row>
@ -437,6 +502,20 @@ em.flush(); // changes to cat are automatically detected and persisted</program
an alternate approach, using detached instances.</para>
</section>
<section>
<title>Detaching a object</title>
<para>An object when loaded in the persistence context is managed by
Hibernate. You can force an object to be detached (ie. no longer managed
by Hibernate) by closing the EntityManager or in a more fine-grained
approach by calling the <methodname>detach()</methodname> method.</para>
<programlisting>Cat cat = em.find( Cat.class, new Long(69) );
...
em.detach(cat);
cat.setName("New name"); //not propatated to the database</programlisting>
</section>
<section>
<title>Modifying detached objects</title>
@ -447,7 +526,7 @@ em.flush(); // changes to cat are automatically detected and persisted</program
approach in a high-concurrency environment usually use versioned data to
ensure isolation for the "long" unit of work.</para>
<para>The EJB3 specifications supports this development model by providing
<para>The JPA specifications supports this development model by providing
for persistence of modifications made to detached instances using the
<methodname>EntityManager.merge()</methodname> method:</para>
@ -559,7 +638,7 @@ secondEntityManager.merge(mate); // save the new instance</programlisting>
<note>
<title>Merging vs. saveOrUpdate/saveOrUpdateCopy</title>
<para>Merging in EJB3 is similar to the
<para>Merging in JPA is similar to the
<literal>saveOrUpdateCopy()</literal> method in native Hibernate.
However, it is not the same as the <literal>saveOrUpdate()</literal>
method, the given instance is not reattached with the persistence
@ -582,14 +661,15 @@ secondEntityManager.merge(mate); // save the new instance</programlisting>
<section>
<title>Flush the persistence context</title>
<para>From time to time the entity manager will execute the SQL DML
statements needed to synchronize the data store with the state of objects
held in memory. This process is called flushing.</para>
<section>
<title>In a transaction</title>
<para>From time to time the entity manager will execute the SQL DML
statements needed to synchronize the data store with the state of
objects held in memory. This process, flush, occurs by default (this is
Hibernate specific and not defined by the specification) at the
following points:</para>
<para>Flush occurs by default (this is Hibernate specific and not
defined by the specification) at the following points:</para>
<itemizedlist>
<listitem>
@ -645,10 +725,10 @@ secondEntityManager.merge(mate); // save the new instance</programlisting>
<para>(Exception: entity instances using application-assigned
identifiers are inserted when they are saved.)</para>
<para>Except when you explicity <methodname>flush()</methodname>, there
are absolutely no guarantees about when the entity manager executes the
JDBC calls, only the order in which they are executed. However,
Hibernate does guarantee that the
<para>Except when you explicitly <methodname>flush()</methodname>, there
are no guarantees about when the entity manager executes the JDBC calls,
only the order in which they are executed. However, Hibernate does
guarantee that the
<methodname>Query.getResultList()</methodname>/<methodname>Query.getSingleResult()</methodname>
will never return stale data; nor will they return wrong data if
executed in an active transaction.</para>
@ -677,7 +757,8 @@ em.getTransaction().commit(); // flush occurs</programlisting>
violates a constraint). TODO: Add link to exception handling.</para>
<para>Hibernate provides more flush modes than the one described in the
EJB3 specification. Please refer to the Hibernate core reference
JPA specification. In particular <literal>FlushMode.MANUAL</literal> for
long running conversation. Please refer to the Hibernate core reference
documentation for more informations.</para>
</section>
@ -730,9 +811,11 @@ em.getTransaction().commit(); // flush occurs</programlisting>
<methodname>persist()</methodname>, <methodname>merge()</methodname>,
<methodname>remove()</methodname>, <methodname>refresh()</methodname> -
there is a corresponding cascade style. Respectively, the cascade styles
are named PERSIST, MERGE, REMOVE, REFRESH. If you want an operation to be
cascaded to associated entity (or collection of entities), you must
indicate that in the association annotation:</para>
are named <literal>PERSIST</literal>, <literal>MERGE</literal>,
<literal>REMOVE</literal>, <literal>REFRESH</literal>,
<literal>DETACH</literal>. If you want an operation to be cascaded to
associated entity (or collection of entities), you must indicate that in
the association annotation:</para>
<programlisting>@OneToOne(cascade=CascadeType.PERSIST)</programlisting>
@ -740,9 +823,16 @@ em.getTransaction().commit(); // flush occurs</programlisting>
<programlisting>@OneToOne(cascade= { CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.REFRESH } )</programlisting>
<para>You may even use CascadeType.ALL to specify that all operations
should be cascaded for a particular association. Remember that by default,
no operation is cascaded.</para>
<para>You may even use <literal>CascadeType.ALL</literal> to specify that
all operations should be cascaded for a particular association. Remember
that by default, no operation is cascaded.</para>
<para>There is an additional cascading mode used to describe orphan
deletion (ie an object no longer linked to an owning object should be
removed automatically by Hibernate. Use
<literal>orphanRemoval=true</literal> on <classname>@OneToOne</classname>
or <classname>@OneToMany</classname>. Check Hibernate Annotations's
documentation for more information.</para>
<para>Hibernate offers more native cascading options, please refer to the
Hibernate Annotations manual and the Hibernate reference guide for more
@ -780,25 +870,58 @@ em.getTransaction().commit(); // flush occurs</programlisting>
<section>
<title>Locking</title>
<para>The default locking system in EJB3 is mostly based on optimistic
locking (ie using a version column to check any concurrency issues). EJB3
has defined an additional mechanism to increase the concurrency
guaranties. You can apply a lock on a given entity (and it's associated
entities if <literal>LOCK</literal> is cascaded) through the
<methodname>lock(Object entity)</methodname> method. Depending on the
concurrency guaranties you requires, you choose a lock mode:</para>
<para>You can define various levels of locking strategies. A lock can be
applied in several ways:</para>
<itemizedlist>
<listitem>
<para><literal>LockMode.READ</literal> prevents dirty-reads and non
repeatable read on a given entity.</para>
<para>via the explicit <methodname>entityManager.lock()</methodname>
method</para>
</listitem>
<listitem>
<para><literal>LockMode.WRITE</literal> prevents dirty-reads and non
repeatable read on a given entity and force an increase of the version
number if any.</para>
<para>via lookup methods on <classname>EntityManager</classname>:
<literal>find()</literal>, <literal>refresh()</literal></para>
</listitem>
<listitem>
<para>on queries: <methodname>query.setLockMode()</methodname></para>
</listitem>
</itemizedlist>
<para>You can use various lock approaches:</para>
<itemizedlist>
<listitem>
<para><literal>OPTIMISTIC</literal> (previously
<literal>READ</literal>): use an optimistic locking scheme where the
version number is compared: the version number is compared and has to
match before the transaction is committed.</para>
</listitem>
<listitem>
<para><literal>OPTIMISTIC_FORCE_INCREMENT</literal> (previously
<literal>WRITE</literal>): use an optimistic locking scheme but force
a version number increase as well: the version number is compared and
has to match before the transaction is committed.</para>
</listitem>
<listitem>
<para><literal>PESSIMISTIC_READ</literal>: apply a database-level read
lock when the lock operation is requested: roughly concurrent readers
are allowed but no writer is allowed.</para>
</listitem>
<listitem>
<para><literal>PESSIMISTIC_WRITE</literal>: apply a database-level
write lock when the lock operation is requested: roughly no reader nor
writer is allowed.</para>
</listitem>
</itemizedlist>
<para>All these locks prevent dirty reads and non-repeatable reads on a
given entity. Optimistic locks enforce the lock as late as possible hoping
nobody changes the data underneath while pessimistic locks enforce the
lock right away and keep it till the transaction is committed.</para>
</section>
</chapter>
</chapter>

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
<?xml version='1.0' encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
@ -22,8 +22,8 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="transactions" revision="1">
<title>Transactions and Concurrency</title>
@ -95,23 +95,22 @@
<para>The most common pattern in a multi-user client/server application
is <emphasis>entitymanager-per-request</emphasis>. In this model, a
request from the client is send to the server (where the EJB3
persistence layer runs), a new <literal>EntityManager</literal> is
opened, and all database operations are executed in this unit of work.
Once the work has been completed (and the response for the client has
been prepared), the persistence context is flushed and closed, as well
as the entity manager object. You would also use a single database
transaction to serve the clients request. The relationship between the
two is one-to-one and this model is a perfect fit for many
applications.</para>
request from the client is send to the server (where the JPA persistence
layer runs), a new <literal>EntityManager</literal> is opened, and all
database operations are executed in this unit of work. Once the work has
been completed (and the response for the client has been prepared), the
persistence context is flushed and closed, as well as the entity manager
object. You would also use a single database transaction to serve the
clients request. The relationship between the two is one-to-one and this
model is a perfect fit for many applications.</para>
<para>This is the default EJB3 persistence model in a Java EE
environment (JTA bounded, transaction-scoped persistence context);
injected (or looked up) entity managers share the same persistence
context for a particular JTA transaction. The beauty of EJB3 is that you
don't have to care about that anymore and just see data access through
entity manager and demarcation of transaction scope on session beans as
completely orthogonal.</para>
<para>This is the default JPA persistence model in a Java EE environment
(JTA bounded, transaction-scoped persistence context); injected (or
looked up) entity managers share the same persistence context for a
particular JTA transaction. The beauty of JPA is that you don't have to
care about that anymore and just see data access through entity manager
and demarcation of transaction scope on session beans as completely
orthogonal.</para>
<para>The challenge is the implementation of this (and other) behavior
outside an EJB3 container: not only has the
@ -187,14 +186,14 @@
transactions (the last one) stores the updated data, all others simply
read data (e.g. in a wizard-style dialog spanning several
request/response cycles). This is easier to implement than it might
sound, especially if you use EJB3 entity manager and persistence context
sound, especially if you use JPA entity manager and persistence context
features:</para>
<itemizedlist>
<listitem>
<para><emphasis>Automatic Versioning</emphasis> - An entity manager
can do automatic optimistic concurrency control for you, it can
automatically detect if a concurrent modification occured during
automatically detect if a concurrent modification occurred during
user think time (usually by comparing version numbers or timestamps
when updating the data in the final resource-local
transaction).</para>
@ -249,9 +248,7 @@
<term>Database Identity</term>
<listitem>
<para>
<literal>foo.getId().equals( bar.getId() )</literal>
</para>
<para><literal>foo.getId().equals( bar.getId() )</literal></para>
</listitem>
</varlistentry>
@ -259,9 +256,7 @@
<term>JVM Identity</term>
<listitem>
<para>
<literal>foo==bar</literal>
</para>
<para><literal>foo==bar</literal></para>
</listitem>
</varlistentry>
</variablelist>
@ -371,8 +366,8 @@
<sect1 id="transactions-demarcation">
<title>Database transaction demarcation</title>
<para>Database (or system) transaction boundaries are always necessary.
No communication with the database can occur outside of a database
<para>Database (or system) transaction boundaries are always necessary. No
communication with the database can occur outside of a database
transaction (this seems to confuse many developers who are used to the
auto-commit mode). Always use clear transaction boundaries, even for
read-only operations. Depending on your isolation level and database
@ -381,8 +376,8 @@
outside a transaction, though, when you'll need to retain modifications in
an <literal>EXTENDED</literal> persistence context.</para>
<para>An EJB3 application can run in non-managed (i.e. standalone, simple
Web- or Swing applications) and managed J2EE environments. In a
<para>A JPA application can run in non-managed (i.e. standalone, simple
Web- or Swing applications) and managed Java EE environments. In a
non-managed environment, an <literal>EntityManagerFactory</literal> is
usually responsible for its own database connection pool. The application
developer has to manually set transaction boundaries, in other words,
@ -418,7 +413,7 @@
<sect2 id="transactions-demarcation-nonmanaged">
<title>Non-managed environment</title>
<para>If an EJB3 persistence layer runs in a non-managed environment,
<para>If an JPA persistence layer runs in a non-managed environment,
database connections are usually handled by Hibernate's pooling
mechanism behind the scenes. The common entity manager and transaction
handling idiom looks like this:</para>
@ -562,6 +557,11 @@ finally {
<programlisting>//CMT idiom through injection
@PersistenceContext(name="sample") EntityManager em;</programlisting>
<para>Or this if you use Java Context and Dependency Injection
(CDI).</para>
<programlisting>@Inject EntityManager em;</programlisting>
<para>In other words, all you have to do in a managed environment is to
inject the <literal>EntityManager</literal>, do your data access work,
and leave the rest to the container. Transaction boundaries are set
@ -569,12 +569,7 @@ finally {
session beans. The lifecycle of the entity manager and persistence
context is completely managed by the container.</para>
<para>TODO: The following paragraph is very confusing, especially the
beginning...</para>
<para>When using particular Hibernate native APIs, one caveat has to be
remembered: <literal>after_statement</literal> connection release mode.
Due to a silly limitation of the JTA spec, it is not possible for
<para>Due to a silly limitation of the JTA spec, it is not possible for
Hibernate to automatically clean up any unclosed
<literal>ScrollableResults</literal> or <literal>Iterator</literal>
instances returned by <literal>scroll()</literal> or
@ -610,23 +605,76 @@ finally {
<itemizedlist>
<listitem>
<para>IllegalArgumentException: something wrong happen</para>
<para><classname>IllegalArgumentException</classname>: something
wrong happen</para>
</listitem>
<listitem>
<para>EntityNotFoundException: an entity was expected but none match
the requirement</para>
<para><classname>EntityNotFoundException</classname>: an entity was
expected but none match the requirement</para>
</listitem>
<listitem>
<para>TransactionRequiredException: this operation has to be in a
<para><classname>NonUniqueResultException</classname>: more than one
entity is found when calling
<methodname>getSingleResult()</methodname></para>
</listitem>
<listitem>
<para>NoResultException: when
<methodname>getSingleResult()</methodname> does not find any
matching entity</para>
</listitem>
<listitem>
<para><classname>EntityExistsException</classname>: an existing
entity is passed to <methodname>persist()</methodname></para>
</listitem>
<listitem>
<para><classname>TransactionRequiredException</classname>: this
operation has to be in a transaction</para>
</listitem>
<listitem>
<para><classname>IllegalStateException</classname>: the entity
manager is used in a wrong way</para>
</listitem>
<listitem>
<para><classname>RollbackException</classname>: a failure happens
during <methodname>commit()</methodname></para>
</listitem>
<listitem>
<para><classname>QueryTimeoutException</classname>: the query takes
longer than the specified timeout (see
<literal>javax.persistence.query.timeout</literal> - this property
is a hint and might not be followed)</para>
</listitem>
<listitem>
<para><classname>PessimisticLockException</classname>: when a lock
cannot be acquired</para>
</listitem>
<listitem>
<para><classname>OptimisticLockException</classname>: an optimistic
lock is failing</para>
</listitem>
<listitem>
<para><classname>LockTimeoutException</classname>: when a lock takes
longer than the expected time to be acquired
(<literal>javax.persistence.lock.timeout</literal> in
milliseconds)</para>
</listitem>
<listitem>
<para><classname>TransactionRequiredException</classname>: an
operation requiring a transaction is executed outside of a
transaction</para>
</listitem>
<listitem>
<para>IllegalStateException: the entity manager is used in a wrong
way</para>
</listitem>
</itemizedlist>
<para>The <literal>HibernateException</literal>, which wraps most of the
@ -694,10 +742,10 @@ finally {
<para>In an <literal>EXTENDED</literal> persistence context, all read only
operations of the entity manager can be executed outside a transaction
(<literal>find()</literal>, <literal>getReference()</literal>,
<literal>refresh()</literal>, and read queries). Some modifications
operations can be executed outside a transaction, but they are queued
until the persistence context join a transaction: this is the case of
<literal>persist()</literal>,
<literal>refresh()</literal>, <methodname>detach()</methodname> and read
queries). Some modifications operations can be executed outside a
transaction, but they are queued until the persistence context join a
transaction: this is the case of <literal>persist()</literal>,
<literal><literal>merge()</literal></literal>,
<literal>remove()</literal>. Some operations cannot be called outside a
transaction: <literal>flush()</literal>, <literal>lock()</literal>, and
@ -706,12 +754,12 @@ finally {
<sect2>
<title>Container Managed Entity Manager</title>
<para>When using an EXTENDED persistence context with a container
managed entity manager, the lifecycle of the persistence context is
binded to the lifecycle of the Stateful Session Bean. Plus if the entity
manager is created outside a transaction, modifications operations
(persist, merge, remove) are queued in the persistence context and not
executed to the database.</para>
<para>When using an <literal>EXTENDED</literal> persistence context with
a container managed entity manager, the lifecycle of the persistence
context is binded to the lifecycle of the Stateful Session Bean. Plus if
the entity manager is created outside a transaction, modifications
operations (persist, merge, remove) are queued in the persistence
context and not executed to the database.</para>
<para>When a method of the stateful session bean involved or starting a
transaction is later called, the entity manager join the transaction.
@ -897,7 +945,7 @@ entityManager.getTransaction().commit();
entityManager.close();</programlisting>
<para>Again, the entity manager will check instance versions during
flush, throwing an exception if conflicting updates occured.</para>
flush, throwing an exception if conflicting updates occurred.</para>
</sect2>
</sect1>
</chapter>
</chapter>