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:
parent
9be297241d
commit
5aa0138ec2
|
@ -67,7 +67,7 @@
|
|||
|
||||
<para>If you use Maven, add the following dependencies</para>
|
||||
|
||||
<programlisting><project ...>
|
||||
<programlisting role="XML" language="XML"><project ...>
|
||||
...
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -100,7 +100,7 @@
|
|||
configuration, so by default, your persistence.xml will be quite
|
||||
minimalist:</para>
|
||||
|
||||
<programlisting><persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
<programlisting role="XML" language="XML"><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">
|
||||
|
@ -116,7 +116,7 @@
|
|||
<para>Here's a more complete example of a
|
||||
<filename><literal>persistence.xml</literal></filename> file</para>
|
||||
|
||||
<programlisting><persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
<programlisting role="XML" language="XML"><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">
|
||||
|
@ -211,7 +211,7 @@
|
|||
environment, the persistence.xml file is not under the same root
|
||||
directory or jar than your domain model).</para>
|
||||
|
||||
<programlisting> <jar-file>file:/home/turin/work/local/lab8/build/classes</jar-file></programlisting>
|
||||
<programlisting role="XML" language="XML"> <jar-file>file:/home/turin/work/local/lab8/build/classes</jar-file></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><validation-mode></literal>. To use it, add a
|
||||
regular property</para>
|
||||
|
||||
<programlisting><property name="javax.persistence.validation.mode">
|
||||
<programlisting role="XML" language="XML"><property name="javax.persistence.validation.mode">
|
||||
ddl
|
||||
</property></programlisting>
|
||||
|
||||
<para>With this approach, you can mix ddl and callback
|
||||
modes:</para>
|
||||
|
||||
<programlisting><property name="javax.persistence.validation.mode">
|
||||
<programlisting role="XML" language="XML"><property name="javax.persistence.validation.mode">
|
||||
ddl, callback
|
||||
</property></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><persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
<programlisting role="XML" language="XML"><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"></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><persistence>
|
||||
<programlisting role="XML" language="XML"><persistence>
|
||||
<persistence-unit name="manager1" transaction-type="RESOURCE_LOCAL">
|
||||
<class>org.hibernate.ejb.test.Cat</class>
|
||||
<class>org.hibernate.ejb.test.Distributor</class>
|
||||
|
@ -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>
|
|
@ -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<?> cats = em.createQuery(
|
||||
"select cat from Cat as cat where cat.birthdate < ?1")
|
||||
.setParameter(1, date, TemporalType.DATE)
|
||||
.getResultList();
|
||||
|
||||
List mothers = em.createQuery(
|
||||
List<?> 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<?> 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<Cat> criteria = builder.createQuery( Cat.class );
|
||||
Root<Cat> cat = criteria.from( Cat.class );
|
||||
criteria.select( cat );
|
||||
criteria.where( builder.lt( cat.get( Cat_.birthdate ), catDate ) );
|
||||
List<Cat> 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<Cat> cats = em.createQuery(
|
||||
"select cat from Cat as cat where cat.birthdate < ?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 > ?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<?> 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<Cat> 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
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue