alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (entitymanagerapi.xml)

This example Hibernate source code file (entitymanagerapi.xml) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

api, cat, cat, hibernate, hibernate, java, java, list, query, sql, sql, the, this, you

The Hibernate entitymanagerapi.xml source code

<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ Copyright (c) 2008, Red Hat Inc or third-party contributors as
  ~ indicated by the @author tags or express copyright attribution
  ~ statements applied by the authors.  All third-party contributions are
  ~ distributed under license by Red Hat Inc.
  ~
  ~ This copyrighted material is made available to anyone wishing to use, modify,
  ~ copy, or redistribute it subject to the terms and conditions of the GNU
  ~ Lesser General Public License, as published by the Free Software Foundation.
  ~
  ~ This program is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  ~ for more details.
  ~
  ~ You should have received a copy of the GNU Lesser General Public License
  ~ along with this distribution; if not, write to:
  ~ Free Software Foundation, Inc.
  ~ 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">
<chapter id="objectstate">
  <title>Working with objects

  <section>
    <title>Entity states

    <para>Like in Hibernate (comparable terms in parentheses), an entity
    instance is in one of the following states:</para>

    <itemizedlist>
      <listitem>
        <para>New (transient): an entity is new if it has just been
        instantiated using the new operator, and it is not associated with a
        persistence context. It has no persistent representation in the
        database and no identifier value has been assigned.</para>
      </listitem>

      <listitem>
        <para>Managed (persistent): a managed entity instance is an instance
        with a persistent identity that is currently associated with a
        persistence context.</para>
      </listitem>

      <listitem>
        <para>Detached: the entity instance is an instance with a persistent
        identity that is no longer associated with a persistence context,
        usually because the persistence context was closed or the instance was
        evicted from the context.</para>
      </listitem>

      <listitem>
        <para>Removed: a removed entity instance is an instance with a
        persistent identity, associated with a persistence context, but
        scheduled for removal from the database.</para>
      </listitem>
    </itemizedlist>

    <para>The EntityManager API allows you to change
    the state of an entity, or in other words, to load and store objects. You
    will find persistence with JPA easier to understand if you think about
    object state management, not managing of SQL statements.</para>
  </section>

  <section>
    <title>Making objects persistent

    <para>Once you've created a new entity instance (using the common
    <literal>new operator) it is in new state.
    You can make it persistent by associating it to an entity manager:</para>

    <programlisting language="JAVA" role="JAVA">DomesticCat fritz = new DomesticCat();
fritz.setColor(Color.GINGER);
fritz.setSex('M');
fritz.setName("Fritz");
em.persist(fritz);</programlisting>

    <para>If the DomesticCat entity type has a generated
    identifier, the value is associated to the instance when
    <code>persist() is called. If the identifier is not automatically
    generated, the application-assigned (usually natural) key value has to be
    set on the instance before <code>persist() is called.
  </section>

  <section>
    <title>Loading an object

    <para>Load an entity instance by its identifier value with the entity
    manager's <code>find() method:

    <programlisting language="JAVA" role="JAVA">cat = em.find(Cat.class, catId);

// You may need to wrap the primitive identifiers
long catId = 1234;
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() method. This is especially
    useful to link a child to its parent without having to load the
    parent.</para>

    <programlisting language="JAVA" role="JAVA">child = new Child();
child.SetName("Henry");
Parent parent = em.getReference(Parent.class, parentId); //no query to the DB
child.setParent(parent);
em.persist(child);</programlisting>

    <para>You can reload an entity instance and it's collections at any time
    using the <code>em.refresh() operation. This is useful when
    database triggers are used to initialize some of the properties of the
    entity. Note that only the entity instance and its collections are
    refreshed unless you specify <literal>REFRESH as a cascade style
    of any associations:</para>

    <programlisting language="JAVA" role="JAVA">em.persist(cat);
em.flush(); // force the SQL insert and triggers to run
em.refresh(cat); //re-read the state (after the trigger executes)</programlisting>
  </section>

  <section>
    <title>Querying objects

    <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
    (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

      <para>JP-QL and SQL queries are represented by an instance of
      <classname>javax.persistence.Query. 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 language="JAVA" role="JAVA">List<?> cats = em.createQuery(
    "select cat from Cat as cat where cat.birthdate < ?1")
    .setParameter(1, date, TemporalType.DATE)
    .getResultList();

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(
    "from Cat as cat where cat.mother = ?1")
    .setEntity(1, pk)
    .getResultList();

Cat mother = (Cat) em.createQuery(
    "select cat.mother from Cat as cat where cat = ?1")
    .setParameter(1, izi)
    .getSingleResult();</programlisting>

      <para>A query is usually executed by invoking
      <methodname>getResultList(). This method loads the
      resulting instances of the query completely into memory. Entity
      instances retrieved by a query are in persistent state. The
      <methodname>getSingleResult() 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 language="JAVA" role="JAVA">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 language="JAVA" role="JAVA">//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

        <para>JPA queries can return tuples of objects if projection is used.
        Each result tuple is returned as an object array:</para>

        <programlisting language="JAVA" role="JAVA">Iterator kittensAndMothers = sess.createQuery(
            "select kitten, mother from Cat kitten join kitten.mother mother")
            .getResultList()
            .iterator();

while ( kittensAndMothers.hasNext() ) {
    Object[] tuple = (Object[]) kittensAndMothers.next();
    Cat kitten = (Cat) tuple[0];
    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" />.
        </note>
      </section>

      <section>
        <title>Scalar results

        <para>Queries may specify a particular property of an entity in the
        select clause, instead of an entity alias. You may call SQL aggregate
        functions as well. Returned non-transactional objects or aggregation
        results are considered "scalar" results and are not entities in
        persistent state (in other words, they are considered "read
        only"):</para>

        <programlisting language="JAVA" role="JAVA">Iterator results = em.createQuery(
        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
        "group by cat.color")
        .getResultList()
        .iterator();

while ( results.hasNext() ) {
    Object[] row = results.next();
    Color type = (Color) row[0];
    Date oldest = (Date) row[1];
    Integer count = (Integer) row[2];
    .....
}</programlisting>
      </section>

      <section>
        <title>Bind parameters

        <para>Both named and positional query parameters are supported, the
        <literal>Query API offers several methods to bind arguments.
        The JPA specification numbers positional parameters from one. Named
        parameters are identifiers of the form <literal>:paramname
        in the query string. Named parameters should be preferred, they are
        more robust and easier to read and understand:</para>

        <programlisting language="JAVA" role="JAVA">// Named parameter (preferred)
Query q = em.createQuery("select cat from DomesticCat cat where cat.name = :name");
q.setParameter("name", "Fritz");
List cats = q.getResultList();

// Positional parameter
Query q = em.createQuery("select cat from DomesticCat cat where cat.name = ?1");
q.setParameter(1, "Izi");
List cats = q.getResultList();

// Named parameter list
List names = new ArrayList();
names.add("Izi");
names.add("Fritz");
Query q = em.createQuery("select cat from DomesticCat cat where cat.name in (:namesList)");
q.setParameter("namesList", names);
List cats = q.list();</programlisting>
      </section>

      <section>
        <title>Pagination

        <para>If you need to specify bounds upon your result set (the maximum
        number of rows you want to retrieve and/or the first row you want to
        retrieve), use the following methods:</para>

        <programlisting language="JAVA" role="JAVA">Query q = em.createQuery("select cat from DomesticCat cat");
q.setFirstResult(20);
q.setMaxResults(10);
List cats = q.getResultList(); //return cats from the 20th position to 29th</programlisting>

        <para>Hibernate knows how to translate this limit query into the
        native SQL of your DBMS.</para>
      </section>

      <section>
        <title>Externalizing named queries

        <para>You may also define named queries through annotations:

        <programlisting language="JAVA" role="JAVA">@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 programmatically to the named query, before
        it is executed:</para>

        <programlisting language="JAVA" role="JAVA">Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
q.setString(1, name);
q.setInt(2, minWeight);
List<?> cats = q.getResultList();</programlisting>

        <para>You can also use the slightly more type-safe approach:

        <programlisting language="JAVA" role="JAVA">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
        metadata, or use Hibernate's native facilities by placing them in XML
        mapping files.</para>
      </section>

      <section>
        <title>Native queries

        <para>You may express a query in SQL, using
        <methodname>createNativeQuery() and let Hibernate take
        care mapping from JDBC result sets to business objects. Use the
        <literal>@SqlResultSetMapping (please see the Hibernate
        Annotations reference documentation on how to map a SQL resultset
        mapping) or the entity mapping (if the column names of the query
        result are the same as the names declared in the entity mapping;
        remember that all entity columns have to be returned for this
        mechanism to work):</para>

        <programlisting language="JAVA" role="JAVA">@SqlResultSetMapping(name="getItem", entities =
        @EntityResult(entityClass=org.hibernate.ejb.test.Item.class, fields= {
            @FieldResult(name="name", column="itemname"),
            @FieldResult(name="descr", column="itemdescription")
        })
)

Query q = em.createNativeQuery("select name as itemname, descr as itemdescription from Item", "getItem");
item = (Item) q.getSingleResult(); //from a resultset

Query q = em.createNativeQuery("select * from Item", Item.class);
item = (Item) q.getSingleResult(); //from a class columns names match the mapping</programlisting>

        <note>
          <para>For more information about scalar support in named queries,
          please refers to the Hibernate Annotations documentation</para>
        </note>
      </section>

      <section>
        <title>Query lock and flush mode

        <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 language="JAVA" role="JAVA">query.setFlushMode(FlushModeType.COMMIT)
     .setLockMode(LockModeType.PESSIMISTIC_READ);</programlisting>

        <note>
          <para>If you want to use FlushMode.MANUAL (ie the
          Hibernate specific flush mode), you will need to use a query hint.
          See below.</para>
        </note>
      </section>

      <section>
        <title>Query hints

        <para>Query hints (for performance optimization, usually) are
        implementation specific. Hints are declared using the
        <methodname>query.setHint(String name, Object value)
        method, or through the <literal>@Named(Native)Query(hints)
        annotation Note that these are not SQL query hints! The Hibernate EJB3
        implementation offers the following query hints:</para>

        <table>
          <title>Hibernate query hints

          <tgroup cols="2">
            <thead>
              <colspec colname="C1" colwidth="1*" />

              <colspec colname="c2" colwidth="3*" />

              <row>
                <entry align="center">Hint

                <entry align="center">Description
              </row>
            </thead>

            <tbody>
              <row>
                <entry>org.hibernate.timeout

                <entry>Query timeout in seconds ( eg. new Integer(10)
                )</entry>
              </row>

              <row>
                <entry>org.hibernate.fetchSize

                <entry>Number of rows fetched by the JDBC driver per roundtrip
                ( eg. new Integer(50) )</entry>
              </row>

              <row>
                <entry>org.hibernate.comment

                <entry>Add a comment to the SQL query, useful for the DBA (
                e.g. new String("fetch all orders in 1 statement") )</entry>
              </row>

              <row>
                <entry>org.hibernate.cacheable

                <entry>Whether or not a query is cacheable ( eg. new
                Boolean(true) ), defaults to false</entry>
              </row>

              <row>
                <entry>org.hibernate.cacheMode

                <entry>Override the cache mode for this query ( eg.
                CacheMode.REFRESH )</entry>
              </row>

              <row>
                <entry>org.hibernate.cacheRegion

                <entry>Cache region of this query ( eg. new
                String("regionName") )</entry>
              </row>

              <row>
                <entry>org.hibernate.readOnly

                <entry>Entities retrieved by this query will be loaded in a
                read-only mode where Hibernate will never dirty-check them or
                make changes persistent ( eg. new Boolean(true) ), default to
                false</entry>
              </row>

              <row>
                <entry>org.hibernate.flushMode

                <entry>Flush mode used for this query (useful to pass
                Hibernate specific flush modes, in particular
                <literal>MANUAL).
              </row>

              <row>
                <entry>org.hibernate.cacheMode

                <entry>Cache mode used for this query
              </row>
            </tbody>
          </tgroup>
        </table>

        <para>The value object accept both the native type or its string
        equivalent (eg. <literal>CaheMode.REFRESH or
        <quote>REFRESH). Please refer to the
        Hibernate reference documentation for more information.</para>
      </section>
    </section>
  </section>

  <section>
    <title>Modifying persistent objects

    <para>Transactional managed instances (ie. objects loaded, saved, created
    or queried by the entity manager) may be manipulated by the application
    and any changes to persistent state will be persisted when the Entity
    manager is flushed (discussed later in this chapter). There is no need to
    call a particular method to make your modifications persistent. A
    straightforward way to update the state of an entity instance is to
    <methodname>find() it, and then manipulate it directly, while
    the persistence context is open:</para>

    <programlisting language="JAVA" role="JAVA">Cat cat = em.find( Cat.class, new Long(69) );
cat.setName("PK");
em.flush();  // changes to cat are automatically detected and persisted</programlisting>

    <para>Sometimes this programming model is inefficient since it would
    require both an SQL SELECT (to load an object) and an SQL UPDATE (to
    persist its updated state) in the same session. Therefore Hibernate offers
    an alternate approach, using detached instances.</para>
  </section>

  <section>
    <title>Detaching a object

    <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() method.

    <programlisting language="JAVA" role="JAVA">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

    <para>Many applications need to retrieve an object in one transaction,
    send it to the presentation layer for manipulation, and later save the
    changes in a new transaction. There can be significant user think and
    waiting time between both transactions. Applications that use this kind of
    approach in a high-concurrency environment usually use versioned data to
    ensure isolation for the "long" unit of work.</para>

    <para>The JPA specifications supports this development model by providing
    for persistence of modifications made to detached instances using the
    <methodname>EntityManager.merge() method:

    <programlisting language="JAVA" role="JAVA">// in the first entity manager
Cat cat = firstEntityManager.find(Cat.class, catId);
Cat potentialMate = new Cat();
firstEntityManager.persist(potentialMate);

// in a higher layer of the application
cat.setMate(potentialMate);

// later, in a new entity manager
secondEntityManager.merge(cat);  // update cat
secondEntityManager.merge(mate); // update mate</programlisting>

    <para>The merge() method merges modifications made to
    the detached instance into the corresponding managed instance, if any,
    without consideration of the state of the persistence context. In other
    words, the merged objects state overrides the persistent entity state in
    the persistence context, if one is already present. The application should
    individually <methodname>merge() detached instances reachable
    from the given detached instance if and only if it wants their state also
    to be persistent. This can be cascaded to associated entities and
    collections, using transitive persistence, see <xref
    linkend="objectstate-transitive" />.</para>
  </section>

  <section>
    <title>Automatic state detection

    <para>The merge operation is clever enough to automatically detect whether
    the merging of the detached instance has to result in an insert or update.
    In other words, you don't have to worry about passing a new instance (and
    not a detached instance) to <literal>merge(), the entity manager
    will figure this out for you:</para>

    <programlisting language="JAVA" role="JAVA">// In the first entity manager
Cat cat = firstEntityManager.find(Cat.class, catID);

// In a higher layer of the application, detached
Cat mate = new Cat();
cat.setMate(mate);

// Later, in a new entity manager
secondEntityManager.merge(cat);   // update existing state
secondEntityManager.merge(mate);  // save the new instance</programlisting>

    <para>The usage and semantics of merge() seems to be
    confusing for new users. Firstly, as long as you are not trying to use
    object state loaded in one entity manager in another new entity manager,
    you should not need to use <methodname>merge() at all. Some
    whole applications will never use this method.</para>

    <para>Usually merge() is used in the following
    scenario:</para>

    <itemizedlist>
      <listitem>
        <para>the application loads an object in the first entity
        manager</para>
      </listitem>

      <listitem>
        <para>the object is passed up to the presentation layer
      </listitem>

      <listitem>
        <para>some modifications are made to the object
      </listitem>

      <listitem>
        <para>the object is passed back down to the business logic
        layer</para>
      </listitem>

      <listitem>
        <para>the application persists these modifications by calling
        <methodname>merge() in a second entity manager
      </listitem>
    </itemizedlist>

    <para>Here is the exact semantic of
    <methodname>merge():

    <itemizedlist>
      <listitem>
        <para>if there is a managed instance with the same identifier
        currently associated with the persistence context, copy the state of
        the given object onto the managed instance</para>
      </listitem>

      <listitem>
        <para>if there is no managed instance currently associated with the
        persistence context, try to load it from the database, or create a new
        managed instance</para>
      </listitem>

      <listitem>
        <para>the managed instance is returned
      </listitem>

      <listitem>
        <para>the given instance does not become associated with the
        persistence context, it remains detached and is usually
        discarded</para>
      </listitem>
    </itemizedlist>

    <note>
      <title>Merging vs. saveOrUpdate/saveOrUpdateCopy

      <para>Merging in JPA is similar to the
      <literal>saveOrUpdateCopy() method in native Hibernate.
      However, it is not the same as the <literal>saveOrUpdate()
      method, the given instance is not reattached with the persistence
      context, but a managed instance is returned by the
      <methodname>merge() method.
    </note>
  </section>

  <section>
    <title>Deleting managed objects

    <para>EntityManager.remove() will remove an
    objects state from the database. Of course, your application might still
    hold a reference to a deleted object. You can think of
    <methodname>remove() as making a persistent instance new (aka
    transient) again. It is not detached, and a merge would result in an
    insertion.</para>
  </section>

  <section>
    <title>Flush the persistence context

    <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

      <para>Flush occurs by default (this is Hibernate specific and not
      defined by the specification) at the following points:</para>

      <itemizedlist>
        <listitem>
          <para>before query execution*
        </listitem>

        <listitem>
          <para>from
          <methodname>javax.persistence.EntityTransaction.commit()*
        </listitem>

        <listitem>
          <para>when EntityManager.flush() is
          called*</para>
        </listitem>
      </itemizedlist>

      <para>(*) if a transaction is active

      <para>The SQL statements are issued in the following order

      <itemizedlist>
        <listitem>
          <para>all entity insertions, in the same order the corresponding
          objects were saved using
          <methodname>EntityManager.persist()
        </listitem>

        <listitem>
          <para>all entity updates
        </listitem>

        <listitem>
          <para>all collection deletions
        </listitem>

        <listitem>
          <para>all collection element deletions, updates and
          insertions</para>
        </listitem>

        <listitem>
          <para>all collection insertions
        </listitem>

        <listitem>
          <para>all entity deletions, in the same order the corresponding
          objects were deleted using
          <methodname>EntityManager.remove()
        </listitem>
      </itemizedlist>

      <para>(Exception: entity instances using application-assigned
      identifiers are inserted when they are saved.)</para>

      <para>Except when you explicitly flush(), 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()/Query.getSingleResult()
      will never return stale data; nor will they return wrong data if
      executed in an active transaction.</para>

      <para>It is possible to change the default behavior so that flush occurs
      less frequently. The <classname>FlushModeType for an entity
      manager defines two different modes: only flush at commit time or flush
      automatically using the explained routine unless
      <methodname>flush() is called explicitly.

      <programlisting language="JAVA" role="JAVA">em = emf.createEntityManager();
Transaction tx = em.getTransaction().begin();
em.setFlushMode(FlushModeType.COMMIT); // allow queries to return stale state

Cat izi = em.find(Cat.class, id);
izi.setName(iznizi);

// might return stale data
em.createQuery("from Cat as cat left outer join cat.kittens kitten").getResultList();

// change to izi is not flushed!
...
em.getTransaction().commit(); // flush occurs</programlisting>

      <para>During flush, an exception might happen (e.g. if a DML operation
      violates a constraint). TODO: Add link to exception handling.</para>

      <para>Hibernate provides more flush modes than the one described in the
      JPA specification. In particular <literal>FlushMode.MANUAL for
      long running conversation. Please refer to the Hibernate core reference
      documentation for more informations.</para>
    </section>

    <section>
      <title>Outside a transaction

      <para>In an EXTENDED persistence context, all read
      only operations of the entity manager can be executed outside a
      transaction (<literal>find(),
      <literal>getReference(), refresh(), 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>merge(),
      <literal>remove(). Some operations cannot be called outside a
      transaction: <literal>flush(), lock(), and
      update/delete queries.</para>
    </section>
  </section>

  <section id="objectstate-transitive" revision="1"
           xreflabel="Transitive persistence">
    <title>Transitive persistence

    <para>It is quite cumbersome to save, delete, or reattach individual
    objects, especially if you deal with a graph of associated objects. A
    common case is a parent/child relationship. Consider the following
    example:</para>

    <para>If the children in a parent/child relationship would be value typed
    (e.g. a collection of addresses or strings), their lifecycle would depend
    on the parent and no further action would be required for convenient
    "cascading" of state changes. When the parent is persisted, the
    value-typed child objects are persisted as well, when the parent is
    removed, the children will be removed, etc. This even works for operations
    such as the removal of a child from the collection; Hibernate will detect
    this and, since value-typed objects can't have shared references, remove
    the child from the database.</para>

    <para>Now consider the same scenario with parent and child objects being
    entities, not value-types (e.g. categories and items, or parent and child
    cats). Entities have their own lifecycle, support shared references (so
    removing an entity from the collection does not mean it can be deleted),
    and there is by default no cascading of state from one entity to any other
    associated entities. The EJB3 specification does not require persistence
    by reachability. It supports a more flexible model of transitive
    persistence, as first seen in Hibernate.</para>

    <para>For each basic operation of the entity manager - including
    <methodname>persist(), merge(),
    <methodname>remove(), refresh() -
    there is a corresponding cascade style. Respectively, the cascade styles
    are named <literal>PERSIST, MERGE,
    <literal>REMOVE, REFRESH,
    <literal>DETACH. 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 language="JAVA" role="JAVA">@OneToOne(cascade=CascadeType.PERSIST)

    <para>Cascading options can be combined:

    <programlisting language="JAVA" role="JAVA">@OneToOne(cascade= { CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.REFRESH } )

    <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>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 on @OneToOne
    or <classname>@OneToMany. 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
    informations.</para>

    <para>Recommendations:

    <itemizedlist>
      <listitem>
        <para>It doesn't usually make sense to enable cascade on a
        <literal>@ManyToOne or @ManyToMany
        association. Cascade is often useful for <literal>@OneToOne
        and <literal>@OneToMany associations.
      </listitem>

      <listitem>
        <para>If the child object's lifespan is bounded by the lifespan of the
        parent object, make the parent a full lifecycle object by specifying
        <literal>CascadeType.ALL and
        <literal>org.hibernate.annotations.CascadeType.DELETE_ORPHAN
        (please refer to the Hibernate reference guide for the semantics of
        orphan delete)</para>
      </listitem>

      <listitem>
        <para>Otherwise, you might not need cascade at all. But if you think
        that you will often be working with the parent and children together
        in the same transaction, and you want to save yourself some typing,
        consider using <code>cascade={PERSIST, MERGE}. These options
        can even make sense for a many-to-many association.</para>
      </listitem>
    </itemizedlist>
  </section>

  <section>
    <title>Locking

    <para>You can define various levels of locking strategies. A lock can be
    applied in several ways:</para>

    <itemizedlist>
      <listitem>
        <para>via the explicit entityManager.lock()
        method</para>
      </listitem>

      <listitem>
        <para>via lookup methods on EntityManager:
        <literal>find(), refresh()
      </listitem>

      <listitem>
        <para>on queries: query.setLockMode()
      </listitem>
    </itemizedlist>

    <para>You can use various lock approaches:

    <itemizedlist>
      <listitem>
        <para>OPTIMISTIC (previously
        <literal>READ): 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>OPTIMISTIC_FORCE_INCREMENT (previously
        <literal>WRITE): 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>PESSIMISTIC_READ: 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>PESSIMISTIC_WRITE: 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>
    <title>Caching

    <para>When the second-level cache is activated (see javax.persistence.cache.retrieveMode which
        accepts <literal>CacheRetrieveMode
        values</para>
      </listitem>

      <listitem>
        <para>javax.persistence.cache.storeMode which
        accepts <classname>CacheStoreMode values
      </listitem>
    </itemizedlist>

    <para>CacheRetrieveMode controls how Hibernate
    accesses information from the second-level cache: <literal>USE
    which is the default or <literal>BYPASS which means ignore the
    cache. <classname>CacheStoreMode controls how Hibernate pushes
    information to the second-level cache: <literal>USE which is the
    default and push data in the cache when reading from and writing to the
    database, <literal>BYPASS which does not insert new data in the
    cache (but can invalidate obsolete data) and
    <classname>REFRESH which does like default but also force data
    to be pushed to the cache on database read even if the data is already
    cached.</para>

    <para>You can set these properties:

    <itemizedlist>
      <listitem>
        <para>on a particular EntityManager via the
        <methodname>setProperty method
      </listitem>

      <listitem>
        <para>on a query via a query hint (setHint
        method)</para>
      </listitem>

      <listitem>
        <para>when calling find() and
        <methodname>refresh() and passing the properties in the
        appropriate <classname>Map
      </listitem>
    </itemizedlist>

    <para>JPA also introduces an API to interrogate the second-level cache and
    evict data manually.</para>

    <programlisting language="JAVA" role="JAVA">Cache cache = entityManagerFactory.getCache();

if ( cache.contains(User.class, userId) ) {
   //load it as we don't hit the DB
}

cache.evict(User.class, userId); //manually evict user form the second-level cache
cache.evict(User.class); //evict all users from the second-level cache
cache.evictAll(); //purge the second-level cache entirely</programlisting>
  </section>

  <section>
    <title>Checking the state of an object

    <para>You can check whether an object is managed by the persistence
    context</para>

    <programlisting language="JAVA" role="JAVA">entityManager.get(Cat.class, catId);
...
boolean isIn = entityManager.contains(cat);
assert isIn;</programlisting>

    <para>You can also check whether an object, an association or a property
    is lazy or not. You can do that independently of the underlying
    persistence provider: </para>

    <programlisting language="JAVA" role="JAVA">PersistenceUtil jpaUtil = Persistence.getPersistenceUtil();
if ( jpaUtil.isLoaded( customer.getAddress() ) {
   //display address if loaded
}
if ( jpaUtil.isLoaded( customer.getOrders ) ) {
   //display orders if loaded
}
if (jpaUtil.isLoaded(customer, "detailedBio") ) {
   //display property detailedBio if loaded
}</programlisting>

    <para>However, if you have access to the entityManagerFactory, we
    recommend you to use:</para>

    <programlisting language="JAVA" role="JAVA">PersistenceUnitUtil jpaUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();

Customer customer = entityManager.get( Customer.class, customerId );

if ( jpaUtil.isLoaded( customer.getAddress() ) {
   //display address if loaded
}
if ( jpaUtil.isLoaded( customer.getOrders ) ) {
   //display orders if loaded
}
if (jpaUtil.isLoaded(customer, "detailedBio") ) {
   //display property detailedBio if loaded
}

log.debug( "Customer id {}", jpaUtil.getIdentifier(customer) );</programlisting>

    <para>The performances are likely to be slightly better and you can get
    the identifier value from an object (using
    <methodname>getIdentifier()).

    <note>
      <para>These are roughly the counterpart methods of
      <methodname>Hibernate.isInitialize.
    </note>
  </section>

  <section>
    <title>Native Hibernate API

    <para>You can always fall back to the underlying
    <classname>Session API from a given
    <classname>EntityManager:

    <programlisting language="JAVA" role="JAVA">Session session = entityManager.unwrap(Session.class);
  </section>
</chapter>

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate entitymanagerapi.xml source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.