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> <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;dependencies&gt;
&lt;dependency&gt; &lt;dependency&gt;
@ -100,7 +100,7 @@
configuration, so by default, your persistence.xml will be quite configuration, so by default, your persistence.xml will be quite
minimalist:</para> 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" 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" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0"&gt; version="2.0"&gt;
@ -116,7 +116,7 @@
<para>Here's a more complete example of a <para>Here's a more complete example of a
<filename><literal>persistence.xml</literal></filename> file</para> <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" 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" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0"&gt; version="2.0"&gt;
@ -211,7 +211,7 @@
environment, the persistence.xml file is not under the same root environment, the persistence.xml file is not under the same root
directory or jar than your domain model).</para> 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> </listitem>
</varlistentry> </varlistentry>
@ -275,7 +275,7 @@
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<para> See Hibernate Annotation's documentation for more <para>See Hibernate Annotation's documentation for more
details.</para> details.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -323,14 +323,14 @@
<literal>&lt;validation-mode&gt;</literal>. To use it, add a <literal>&lt;validation-mode&gt;</literal>. To use it, add a
regular property</para> 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 ddl
&lt;/property&gt;</programlisting> &lt;/property&gt;</programlisting>
<para>With this approach, you can mix ddl and callback <para>With this approach, you can mix ddl and callback
modes:</para> 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 ddl, callback
&lt;/property&gt;</programlisting> &lt;/property&gt;</programlisting>
</listitem> </listitem>
@ -427,7 +427,7 @@
the version embedded in the hibernate-entitymanager.jar. It won't fetch the version embedded in the hibernate-entitymanager.jar. It won't fetch
the resource from the internet.</para> 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" 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" 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> version="2.0"&gt;</programlisting>
@ -441,7 +441,7 @@
<classname>EntityManager</classname>. The bootstrap class is <classname>EntityManager</classname>. The bootstrap class is
<classname>javax.persistence.Persistence</classname>, e.g.</para> <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 //or
@ -528,8 +528,6 @@ EntityManagerFactory programmaticEmf =
reference documentation for a complete listing. There are however a reference documentation for a complete listing. There are however a
couple of properties available in the EJB3 provider only.</para> couple of properties available in the EJB3 provider only.</para>
<para></para>
<table> <table>
<title>Hibernate Entity Manager specific properties</title> <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> <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;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.Cat&lt;/class&gt;
&lt;class&gt;org.hibernate.ejb.test.Distributor&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> <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 = EntityManagerFactory emf =
cfg.addProperties( properties ) //add some properties cfg.addProperties( properties ) //add some properties
.setInterceptor( myInterceptorImpl ) // set an interceptor .setInterceptor( myInterceptorImpl ) // set an interceptor
@ -714,9 +712,9 @@ EntityManagerFactory emf =
<title>Event listeners</title> <title>Event listeners</title>
<para>Hibernate Entity Manager needs to enhance Hibernate core to <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, 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> event listeners to the list given below.</para>
<table> <table>
@ -793,15 +791,13 @@ EntityManagerFactory emf =
<row> <row>
<entry>pre-insert</entry> <entry>pre-insert</entry>
<entry>org.hibernate.secure.JACCPreInsertEventListener, <entry>org.hibernate.secure.JACCPreInsertEventListener</entry>
org.hibernate.valitator.event.ValidateEventListener</entry>
</row> </row>
<row> <row>
<entry>pre-insert</entry> <entry>pre-insert</entry>
<entry>org.hibernate.secure.JACCPreUpdateEventListener, <entry>org.hibernate.secure.JACCPreUpdateEventListener</entry>
org.hibernate.valitator.event.ValidateEventListener</entry>
</row> </row>
<row> <row>
@ -861,7 +857,7 @@ EntityManagerFactory emf =
<classname>Persistence</classname> class is bootstrap class to create an <classname>Persistence</classname> class is bootstrap class to create an
entity manager factory.</para> entity manager factory.</para>
<programlisting>// Use persistence.xml configuration <programlisting role="JAVA" language="JAVA">// Use persistence.xml configuration
EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1") EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1")
EntityManager em = emf.createEntityManager(); // Retrieve an application managed entity manager EntityManager em = emf.createEntityManager(); // Retrieve an application managed entity manager
// Work with the EM // Work with the EM

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 ~ Hibernate, Relational Persistence for Idiomatic Java
~ ~
@ -22,15 +22,15 @@
~ 51 Franklin Street, Fifth Floor ~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA ~ Boston, MA 02110-1301 USA
--> -->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="objectstate"> <chapter id="objectstate">
<title>Working with objects</title> <title>Working with objects</title>
<section> <section>
<title>Entity states</title> <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> instance is in one of the following states:</para>
<itemizedlist> <itemizedlist>
@ -63,7 +63,7 @@
<para>The <classname>EntityManager</classname> API allows you to change <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 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> object state management, not managing of SQL statements.</para>
</section> </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 <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 just having a reference to it (ie a proxy). You can get this reference
using the <literal>getReference()</literal> method. This is especially 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(); <programlisting>child = new Child();
child.SetName("Henry"); 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 <para>If you don't know the identifier values of the objects you are
looking for, you need a query. The Hibernate EntityManager implementation looking for, you need a query. The Hibernate EntityManager implementation
supports an easy-to-use but powerful object-oriented query language supports an easy-to-use but powerful object-oriented query language
(EJB3-QL) which has been inspired by HQL (and vice-versa). Both query (JP-QL) which has been inspired by HQL (and vice-versa). HQL is strictly
languages are portable across databases, the use entity and property names speaking a superset of JP-QL. Both query languages are portable across
as identifiers (instead of table and column names). You may also express databases, the use entity and property names as identifiers (instead of
your query in the native SQL of your database, with optional support from table and column names). You may also express your query in the native SQL
EJB3 for result set conversion into Java business objects.</para> of your database, with optional support from JPA for result set conversion
into Java business objects.</para>
<section> <section>
<title>Executing queries</title> <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 <classname>javax.persistence.Query</classname>. This interface offers
methods for parameter binding, result set handling, and for execution of methods for parameter binding, result set handling, and for execution of
the query. Queries are always created using the current entity the query. Queries are always created using the current entity
manager:</para> 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") "select cat from Cat as cat where cat.birthdate &lt; ?1")
.setParameter(1, date, TemporalType.DATE) .setParameter(1, date, TemporalType.DATE)
.getResultList(); .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") "select mother from Cat as cat join cat.mother as mother where cat.name = ?1")
.setParameter(1, name) .setParameter(1, name)
.getResultList(); .getResultList();
List kittens = em.createQuery( List&lt;?&gt; kittens = em.createQuery(
"from Cat as cat where cat.mother = ?1") "from Cat as cat where cat.mother = ?1")
.setEntity(1, pk) .setEntity(1, pk)
.getResultList(); .getResultList();
@ -165,17 +167,43 @@ Cat mother = (Cat) em.createQuery(
<para>A query is usually executed by invoking <para>A query is usually executed by invoking
<methodname>getResultList()</methodname>. This method loads the <methodname>getResultList()</methodname>. This method loads the
resulting instances of the query completly into memory. Entity instances resulting instances of the query completely into memory. Entity
retrieved by a query are in persistent state. The instances retrieved by a query are in persistent state. The
<methodname>getSingleResult() </methodname>method offers a shortcut if <methodname>getSingleResult() </methodname>method offers a shortcut if
you know your query will only return a single object.</para> 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> <section>
<title>Projection</title> <title>Projection</title>
<para>An EJB3QL query queries can return tuples of objects if <para>JPA queries can return tuples of objects if projection is used.
projection is used. Each result tuple is returned as an object Each result tuple is returned as an object array:</para>
array:</para>
<programlisting>Iterator kittensAndMothers = sess.createQuery( <programlisting>Iterator kittensAndMothers = sess.createQuery(
"select kitten, mother from Cat kitten join kitten.mother mother") "select kitten, mother from Cat kitten join kitten.mother mother")
@ -188,6 +216,11 @@ while ( kittensAndMothers.hasNext() ) {
Cat mother = (Cat) tuple[1]; Cat mother = (Cat) tuple[1];
.... ....
}</programlisting> }</programlisting>
<note>
<para>The criteria API provides a type-safe approach to projection
results. Check out <xref linkend="querycriteria-tuple" />.</para>
</note>
</section> </section>
<section> <section>
@ -220,9 +253,9 @@ while ( results.hasNext() ) {
<para>Both named and positional query parameters are supported, the <para>Both named and positional query parameters are supported, the
<literal>Query</literal> API offers several methods to bind arguments. <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> 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> more robust and easier to read and understand:</para>
<programlisting>// Named parameter (preferred) <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", <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> 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> it is executed:</para>
<programlisting>Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight"); <programlisting>Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
q.setString(1, name); q.setString(1, name);
q.setInt(2, minWeight); 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 <para>Note that the actual program code is independent of the query
language that is used, you may also define native SQL queries in 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> </note>
</section> </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> <section>
<title>Query hints</title> <title>Query hints</title>
@ -395,7 +458,9 @@ item = (Item) q.getSingleResult(); //from a class columns names match the mappin
<row> <row>
<entry>org.hibernate.flushMode</entry> <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>
<row> <row>
@ -437,6 +502,20 @@ em.flush(); // changes to cat are automatically detected and persisted</program
an alternate approach, using detached instances.</para> an alternate approach, using detached instances.</para>
</section> </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> <section>
<title>Modifying detached objects</title> <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 approach in a high-concurrency environment usually use versioned data to
ensure isolation for the "long" unit of work.</para> 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 for persistence of modifications made to detached instances using the
<methodname>EntityManager.merge()</methodname> method:</para> <methodname>EntityManager.merge()</methodname> method:</para>
@ -559,7 +638,7 @@ secondEntityManager.merge(mate); // save the new instance</programlisting>
<note> <note>
<title>Merging vs. saveOrUpdate/saveOrUpdateCopy</title> <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. <literal>saveOrUpdateCopy()</literal> method in native Hibernate.
However, it is not the same as the <literal>saveOrUpdate()</literal> However, it is not the same as the <literal>saveOrUpdate()</literal>
method, the given instance is not reattached with the persistence method, the given instance is not reattached with the persistence
@ -582,14 +661,15 @@ secondEntityManager.merge(mate); // save the new instance</programlisting>
<section> <section>
<title>Flush the persistence context</title> <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> <section>
<title>In a transaction</title> <title>In a transaction</title>
<para>From time to time the entity manager will execute the SQL DML <para>Flush occurs by default (this is Hibernate specific and not
statements needed to synchronize the data store with the state of defined by the specification) at the following points:</para>
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>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
@ -645,10 +725,10 @@ secondEntityManager.merge(mate); // save the new instance</programlisting>
<para>(Exception: entity instances using application-assigned <para>(Exception: entity instances using application-assigned
identifiers are inserted when they are saved.)</para> identifiers are inserted when they are saved.)</para>
<para>Except when you explicity <methodname>flush()</methodname>, there <para>Except when you explicitly <methodname>flush()</methodname>, there
are absolutely no guarantees about when the entity manager executes the are no guarantees about when the entity manager executes the JDBC calls,
JDBC calls, only the order in which they are executed. However, only the order in which they are executed. However, Hibernate does
Hibernate does guarantee that the guarantee that the
<methodname>Query.getResultList()</methodname>/<methodname>Query.getSingleResult()</methodname> <methodname>Query.getResultList()</methodname>/<methodname>Query.getSingleResult()</methodname>
will never return stale data; nor will they return wrong data if will never return stale data; nor will they return wrong data if
executed in an active transaction.</para> 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> violates a constraint). TODO: Add link to exception handling.</para>
<para>Hibernate provides more flush modes than the one described in the <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> documentation for more informations.</para>
</section> </section>
@ -730,9 +811,11 @@ em.getTransaction().commit(); // flush occurs</programlisting>
<methodname>persist()</methodname>, <methodname>merge()</methodname>, <methodname>persist()</methodname>, <methodname>merge()</methodname>,
<methodname>remove()</methodname>, <methodname>refresh()</methodname> - <methodname>remove()</methodname>, <methodname>refresh()</methodname> -
there is a corresponding cascade style. Respectively, the cascade styles there is a corresponding cascade style. Respectively, the cascade styles
are named PERSIST, MERGE, REMOVE, REFRESH. If you want an operation to be are named <literal>PERSIST</literal>, <literal>MERGE</literal>,
cascaded to associated entity (or collection of entities), you must <literal>REMOVE</literal>, <literal>REFRESH</literal>,
indicate that in the association annotation:</para> <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> <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> <programlisting>@OneToOne(cascade= { CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.REFRESH } )</programlisting>
<para>You may even use CascadeType.ALL to specify that all operations <para>You may even use <literal>CascadeType.ALL</literal> to specify that
should be cascaded for a particular association. Remember that by default, all operations should be cascaded for a particular association. Remember
no operation is cascaded.</para> 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 <para>Hibernate offers more native cascading options, please refer to the
Hibernate Annotations manual and the Hibernate reference guide for more Hibernate Annotations manual and the Hibernate reference guide for more
@ -780,25 +870,58 @@ em.getTransaction().commit(); // flush occurs</programlisting>
<section> <section>
<title>Locking</title> <title>Locking</title>
<para>The default locking system in EJB3 is mostly based on optimistic <para>You can define various levels of locking strategies. A lock can be
locking (ie using a version column to check any concurrency issues). EJB3 applied in several ways:</para>
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>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para><literal>LockMode.READ</literal> prevents dirty-reads and non <para>via the explicit <methodname>entityManager.lock()</methodname>
repeatable read on a given entity.</para> method</para>
</listitem> </listitem>
<listitem> <listitem>
<para><literal>LockMode.WRITE</literal> prevents dirty-reads and non <para>via lookup methods on <classname>EntityManager</classname>:
repeatable read on a given entity and force an increase of the version <literal>find()</literal>, <literal>refresh()</literal></para>
number if any.</para> </listitem>
<listitem>
<para>on queries: <methodname>query.setLockMode()</methodname></para>
</listitem> </listitem>
</itemizedlist> </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> </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 ~ Hibernate, Relational Persistence for Idiomatic Java
~ ~
@ -22,8 +22,8 @@
~ 51 Franklin Street, Fifth Floor ~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA ~ Boston, MA 02110-1301 USA
--> -->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="transactions" revision="1"> <chapter id="transactions" revision="1">
<title>Transactions and Concurrency</title> <title>Transactions and Concurrency</title>
@ -95,23 +95,22 @@
<para>The most common pattern in a multi-user client/server application <para>The most common pattern in a multi-user client/server application
is <emphasis>entitymanager-per-request</emphasis>. In this model, a is <emphasis>entitymanager-per-request</emphasis>. In this model, a
request from the client is send to the server (where the EJB3 request from the client is send to the server (where the JPA persistence
persistence layer runs), a new <literal>EntityManager</literal> is layer runs), a new <literal>EntityManager</literal> is opened, and all
opened, and all database operations are executed in this unit of work. database operations are executed in this unit of work. Once the work has
Once the work has been completed (and the response for the client has been completed (and the response for the client has been prepared), the
been prepared), the persistence context is flushed and closed, as well persistence context is flushed and closed, as well as the entity manager
as the entity manager object. You would also use a single database object. You would also use a single database transaction to serve the
transaction to serve the clients request. The relationship between the clients request. The relationship between the two is one-to-one and this
two is one-to-one and this model is a perfect fit for many model is a perfect fit for many applications.</para>
applications.</para>
<para>This is the default EJB3 persistence model in a Java EE <para>This is the default JPA persistence model in a Java EE environment
environment (JTA bounded, transaction-scoped persistence context); (JTA bounded, transaction-scoped persistence context); injected (or
injected (or looked up) entity managers share the same persistence looked up) entity managers share the same persistence context for a
context for a particular JTA transaction. The beauty of EJB3 is that you particular JTA transaction. The beauty of JPA is that you don't have to
don't have to care about that anymore and just see data access through care about that anymore and just see data access through entity manager
entity manager and demarcation of transaction scope on session beans as and demarcation of transaction scope on session beans as completely
completely orthogonal.</para> orthogonal.</para>
<para>The challenge is the implementation of this (and other) behavior <para>The challenge is the implementation of this (and other) behavior
outside an EJB3 container: not only has the outside an EJB3 container: not only has the
@ -187,14 +186,14 @@
transactions (the last one) stores the updated data, all others simply transactions (the last one) stores the updated data, all others simply
read data (e.g. in a wizard-style dialog spanning several read data (e.g. in a wizard-style dialog spanning several
request/response cycles). This is easier to implement than it might 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> features:</para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para><emphasis>Automatic Versioning</emphasis> - An entity manager <para><emphasis>Automatic Versioning</emphasis> - An entity manager
can do automatic optimistic concurrency control for you, it can 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 user think time (usually by comparing version numbers or timestamps
when updating the data in the final resource-local when updating the data in the final resource-local
transaction).</para> transaction).</para>
@ -249,9 +248,7 @@
<term>Database Identity</term> <term>Database Identity</term>
<listitem> <listitem>
<para> <para><literal>foo.getId().equals( bar.getId() )</literal></para>
<literal>foo.getId().equals( bar.getId() )</literal>
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -259,9 +256,7 @@
<term>JVM Identity</term> <term>JVM Identity</term>
<listitem> <listitem>
<para> <para><literal>foo==bar</literal></para>
<literal>foo==bar</literal>
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
@ -371,8 +366,8 @@
<sect1 id="transactions-demarcation"> <sect1 id="transactions-demarcation">
<title>Database transaction demarcation</title> <title>Database transaction demarcation</title>
<para>Database (or system) transaction boundaries are always necessary. <para>Database (or system) transaction boundaries are always necessary. No
No communication with the database can occur outside of a database communication with the database can occur outside of a database
transaction (this seems to confuse many developers who are used to the transaction (this seems to confuse many developers who are used to the
auto-commit mode). Always use clear transaction boundaries, even for auto-commit mode). Always use clear transaction boundaries, even for
read-only operations. Depending on your isolation level and database 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 outside a transaction, though, when you'll need to retain modifications in
an <literal>EXTENDED</literal> persistence context.</para> an <literal>EXTENDED</literal> persistence context.</para>
<para>An EJB3 application can run in non-managed (i.e. standalone, simple <para>A JPA application can run in non-managed (i.e. standalone, simple
Web- or Swing applications) and managed J2EE environments. In a Web- or Swing applications) and managed Java EE environments. In a
non-managed environment, an <literal>EntityManagerFactory</literal> is non-managed environment, an <literal>EntityManagerFactory</literal> is
usually responsible for its own database connection pool. The application usually responsible for its own database connection pool. The application
developer has to manually set transaction boundaries, in other words, developer has to manually set transaction boundaries, in other words,
@ -418,7 +413,7 @@
<sect2 id="transactions-demarcation-nonmanaged"> <sect2 id="transactions-demarcation-nonmanaged">
<title>Non-managed environment</title> <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 database connections are usually handled by Hibernate's pooling
mechanism behind the scenes. The common entity manager and transaction mechanism behind the scenes. The common entity manager and transaction
handling idiom looks like this:</para> handling idiom looks like this:</para>
@ -562,6 +557,11 @@ finally {
<programlisting>//CMT idiom through injection <programlisting>//CMT idiom through injection
@PersistenceContext(name="sample") EntityManager em;</programlisting> @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 <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, inject the <literal>EntityManager</literal>, do your data access work,
and leave the rest to the container. Transaction boundaries are set 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 session beans. The lifecycle of the entity manager and persistence
context is completely managed by the container.</para> context is completely managed by the container.</para>
<para>TODO: The following paragraph is very confusing, especially the <para>Due to a silly limitation of the JTA spec, it is not possible for
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
Hibernate to automatically clean up any unclosed Hibernate to automatically clean up any unclosed
<literal>ScrollableResults</literal> or <literal>Iterator</literal> <literal>ScrollableResults</literal> or <literal>Iterator</literal>
instances returned by <literal>scroll()</literal> or instances returned by <literal>scroll()</literal> or
@ -610,23 +605,76 @@ finally {
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para>IllegalArgumentException: something wrong happen</para> <para><classname>IllegalArgumentException</classname>: something
wrong happen</para>
</listitem> </listitem>
<listitem> <listitem>
<para>EntityNotFoundException: an entity was expected but none match <para><classname>EntityNotFoundException</classname>: an entity was
the requirement</para> expected but none match the requirement</para>
</listitem> </listitem>
<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> transaction</para>
</listitem> </listitem>
<listitem>
<para>IllegalStateException: the entity manager is used in a wrong
way</para>
</listitem>
</itemizedlist> </itemizedlist>
<para>The <literal>HibernateException</literal>, which wraps most of the <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 <para>In an <literal>EXTENDED</literal> persistence context, all read only
operations of the entity manager can be executed outside a transaction operations of the entity manager can be executed outside a transaction
(<literal>find()</literal>, <literal>getReference()</literal>, (<literal>find()</literal>, <literal>getReference()</literal>,
<literal>refresh()</literal>, and read queries). Some modifications <literal>refresh()</literal>, <methodname>detach()</methodname> and read
operations can be executed outside a transaction, but they are queued queries). Some modifications operations can be executed outside a
until the persistence context join a transaction: this is the case of transaction, but they are queued until the persistence context join a
<literal>persist()</literal>, transaction: this is the case of <literal>persist()</literal>,
<literal><literal>merge()</literal></literal>, <literal><literal>merge()</literal></literal>,
<literal>remove()</literal>. Some operations cannot be called outside a <literal>remove()</literal>. Some operations cannot be called outside a
transaction: <literal>flush()</literal>, <literal>lock()</literal>, and transaction: <literal>flush()</literal>, <literal>lock()</literal>, and
@ -706,12 +754,12 @@ finally {
<sect2> <sect2>
<title>Container Managed Entity Manager</title> <title>Container Managed Entity Manager</title>
<para>When using an EXTENDED persistence context with a container <para>When using an <literal>EXTENDED</literal> persistence context with
managed entity manager, the lifecycle of the persistence context is a container managed entity manager, the lifecycle of the persistence
binded to the lifecycle of the Stateful Session Bean. Plus if the entity context is binded to the lifecycle of the Stateful Session Bean. Plus if
manager is created outside a transaction, modifications operations the entity manager is created outside a transaction, modifications
(persist, merge, remove) are queued in the persistence context and not operations (persist, merge, remove) are queued in the persistence
executed to the database.</para> context and not executed to the database.</para>
<para>When a method of the stateful session bean involved or starting a <para>When a method of the stateful session bean involved or starting a
transaction is later called, the entity manager join the transaction. transaction is later called, the entity manager join the transaction.
@ -897,7 +945,7 @@ entityManager.getTransaction().commit();
entityManager.close();</programlisting> entityManager.close();</programlisting>
<para>Again, the entity manager will check instance versions during <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> </sect2>
</sect1> </sect1>
</chapter> </chapter>