| <html><head> |
| <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> |
| <title>3. Object Locking</title><link rel="stylesheet" href="css/docbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.72.0"><link rel="start" href="manual.html" title="Apache OpenJPA User's Guide"><link rel="up" href="ref_guide_runtime.html" title="Chapter 9. Runtime Extensions"><link rel="prev" href="ref_guide_runtime_jpa.html" title="2. JPA Extensions"><link rel="next" href="ref_guide_savepoints.html" title="4. Savepoints"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3. |
| Object Locking |
| </th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ref_guide_runtime_jpa.html">Prev</a> </td><th width="60%" align="center">Chapter 9. |
| Runtime Extensions |
| </th><td width="20%" align="right"> <a accesskey="n" href="ref_guide_savepoints.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="ref_guide_locking"></a>3. |
| Object Locking |
| </h2></div></div></div><div class="toc"><dl><dt><span class="section"><a href="ref_guide_locking.html#ref_guide_locking_default">3.1. |
| Configuring Default Locking |
| </a></span></dt><dt><span class="section"><a href="ref_guide_locking.html#ref_guide_locking_runtime">3.2. |
| Configuring Lock Levels at Runtime |
| </a></span></dt><dt><span class="section"><a href="ref_guide_locking.html#ref_guide_locking_apis">3.3. |
| Object Locking APIs |
| </a></span></dt><dt><span class="section"><a href="ref_guide_locking.html#ref_guide_locking_lockmgr">3.4. |
| Lock Manager |
| </a></span></dt><dt><span class="section"><a href="ref_guide_locking.html#ref_guide_locking_rules">3.5. |
| Rules for Locking Behavior |
| </a></span></dt><dt><span class="section"><a href="ref_guide_locking.html#ref_guide_locking_issues">3.6. |
| Known Issues and Limitations |
| </a></span></dt></dl></div><a class="indexterm" name="d0e27471"></a><p> |
| Controlling how and when objects are locked is an important part of maximizing |
| the performance of your application under load. This section describes OpenJPA's |
| APIs for explicit locking, as well as its rules for implicit locking. |
| </p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_locking_default"></a>3.1. |
| Configuring Default Locking |
| </h3></div></div></div><a class="indexterm" name="d0e27479"></a><p> |
| <a class="indexterm" name="d0e27486"></a> |
| <a class="indexterm" name="d0e27492"></a> |
| <a class="indexterm" name="d0e27496"></a> |
| You can control OpenJPA's default transactional read and write lock levels |
| through the <a href="ref_guide_conf_openjpa.html#openjpa.ReadLockLevel" title="5.51. openjpa.ReadLockLevel"><code class="literal"> |
| openjpa.ReadLockLevel</code></a> and |
| <a href="ref_guide_conf_openjpa.html#openjpa.WriteLockLevel" title="5.59. openjpa.WriteLockLevel"><code class="literal">openjpa.WriteLockLevel</code> |
| </a> configuration properties. Each property accepts a value of <code class="literal"> |
| none</code>, <code class="literal">read</code>, <code class="literal">write</code>, or a number |
| corresponding to a lock level defined by the |
| <a href="ref_guide_locking.html#ref_guide_locking_lockmgr" title="3.4. Lock Manager">lock manager</a> in use. These |
| properties apply only to non-optimistic transactions; during optimistic |
| transactions, OpenJPA never locks objects by default. |
| </p><p> |
| <a class="indexterm" name="d0e27523"></a> |
| <a class="indexterm" name="d0e27527"></a> |
| You can control the default amount of time OpenJPA will wait when trying to |
| obtain locks through the <a href="ref_guide_conf_openjpa.html#openjpa.LockTimeout" title="5.37. openjpa.LockTimeout"><code class="literal"> |
| openjpa.LockTimeout</code></a> configuration property. Set this property |
| to the number of milliseconds you are willing to wait for a lock before OpenJPA |
| will throw an exception, or to -1 for no limit. It defaults to -1. |
| </p><div class="example"><a name="ref_guide_locking_default_conf"></a><p class="title"><b>Example 9.3. |
| Setting Default Lock Levels |
| </b></p><div class="example-contents"><pre class="programlisting"> |
| <property name="openjpa.ReadLockLevel" value="none"/> |
| <property name="openjpa.WriteLockLevel" value="write"/> |
| <property name="openjpa.LockTimeout" value="30000"/> |
| </pre></div></div><br class="example-break"></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_locking_runtime"></a>3.2. |
| Configuring Lock Levels at Runtime |
| </h3></div></div></div><a class="indexterm" name="d0e27545"></a><p> |
| At runtime, you can override the default lock levels through the <code class="classname"> |
| FetchPlan</code> interface described above. At the beginning of each |
| datastore transaction, OpenJPA initializes the <code class="classname"> EntityManager |
| </code>'s fetch plan with the default lock levels and timeouts described |
| in the previous section. By changing the fetch plan's locking properties, you |
| can control how objects loaded at different points in the transaction are |
| locked. You can also use the fetch plan of an individual <code class="classname">Query |
| </code> to apply your locking changes only to objects loaded through that |
| <code class="classname">Query</code>. |
| </p><pre class="programlisting"> |
| public LockModeType getReadLockMode(); |
| public FetchPlan setReadLockMode(LockModeType mode); |
| public LockModeType getWriteLockMode(); |
| public FetchPlan setWriteLockMode(LockModeType mode); |
| long getLockTimeout(); |
| FetchPlan setLockTimeout(long timeout); |
| </pre><p> |
| Controlling locking through these runtime APIs works even during optimistic |
| transactions. At the end of the transaction, OpenJPA resets the fetch plan's |
| lock levels to <code class="literal">none</code>. You cannot lock objects outside of a |
| transaction. |
| </p><div class="example"><a name="ref_guide_locking_fetch"></a><p class="title"><b>Example 9.4. |
| Setting Runtime Lock Levels |
| </b></p><div class="example-contents"><pre class="programlisting"> |
| import org.apache.openjpa.persistence.*; |
| |
| ... |
| |
| EntityManager em = ...; |
| em.getTransaction().begin(); |
| |
| // load stock we know we're going to update at write lock mode |
| Query q = em.createQuery("select s from Stock s where symbol = :s"); |
| q.setParameter("s", symbol); |
| OpenJPAQuery oq = OpenJPAPersistence.cast(q); |
| FetchPlan fetch = oq.getFetchPlan (); |
| fetch.setReadLockMode(LockModeType.WRITE); |
| fetch.setLockTimeout(3000); // 3 seconds |
| Stock stock = (Stock) q.getSingleResult(); |
| |
| // load an object we don't need locked at none lock mode |
| fetch = OpenJPAPersistence.cast(em).getFetchPlan(); |
| fetch.setReadLockMode(null); |
| Market market = em.find(Market.class, marketId); |
| |
| stock.setPrice(market.calculatePrice(stock)); |
| em.getTransaction().commit(); |
| </pre></div></div><br class="example-break"></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_locking_apis"></a>3.3. |
| Object Locking APIs |
| </h3></div></div></div><a class="indexterm" name="d0e27579"></a><p> |
| In addition to allowing you to control implicit locking levels, OpenJPA provides |
| explicit APIs to lock objects and to retrieve their current lock level. |
| </p><pre class="programlisting"> |
| public LockModeType OpenJPAEntityManager.getLockMode(Object pc); |
| </pre><p> |
| Returns the level at which the given object is currently locked. |
| </p><p> |
| In addition to the standard |
| <a xmlns:xlink="http://www.w3.org/1999/xlink" href="http://java.sun.com/javaee/5/docs/api/javax/persistence/EntityManager.html" target="_top"> |
| <code class="methodname">EntityManager.lock(Object, LockModeType)</code></a> |
| method, the |
| <a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/persistence/OpenJPAEntityManager.html" target="_top"> |
| <code class="classname">OpenJPAEntityManager</code></a> exposes the following |
| methods to lock objects explicitly: |
| </p><pre class="programlisting"> |
| public void lock(Object pc); |
| public void lock(Object pc, LockModeType mode, long timeout); |
| public void lockAll(Object... pcs); |
| public void lockAll(Object... pcs, LockModeType mode, long timeout); |
| public void lockAll(Collection pcs); |
| public void lockAll(Collection pcs, LockModeType mode, long timeout); |
| </pre><p> |
| Methods that do not take a lock level or timeout parameter default to the |
| current fetch plan. The example below demonstrates these methods in action. |
| </p><div class="example"><a name="ref_guide_locking_explicit"></a><p class="title"><b>Example 9.5. |
| Locking APIs |
| </b></p><div class="example-contents"><pre class="programlisting"> |
| import org.apache.openjpa.persistence.*; |
| |
| // retrieve the lock level of an object |
| OpenJPAEntityManager oem = OpenJPAPersistence.cast(em); |
| Stock stock = ...; |
| LockModeType level = oem.getLockMode(stock); |
| if (level == OpenJPAModeType.WRITE) ... |
| |
| ... |
| |
| oem.setOptimistic(true); |
| oem.getTransaction().begin (); |
| |
| // override default of not locking during an opt trans to lock stock object |
| oem.lock(stock, LockModeType.WRITE, 1000); |
| stock.setPrice(market.calculatePrice(stock)); |
| |
| oem.getTransaction().commit(); |
| </pre></div></div><br class="example-break"></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_locking_lockmgr"></a>3.4. |
| Lock Manager |
| </h3></div></div></div><a class="indexterm" name="d0e27614"></a><p> |
| <a class="indexterm" name="d0e27621"></a> |
| OpenJPA delegates the actual work of locking objects to the system's |
| <a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/kernel/LockManager.html" target="_top"><code class="classname"> |
| org.apache.openjpa.kernel.LockManager</code></a>. This plugin is |
| controlled by the <a href="ref_guide_conf_openjpa.html#openjpa.LockManager" title="5.36. openjpa.LockManager"><code class="literal"> |
| openjpa.LockManager</code></a> configuration property. You can write your |
| own lock manager, or use one of the bundled options: |
| </p><div class="itemizedlist"><ul type="disc"><li><p> |
| <code class="literal">pessimistic</code>: This is an alias for the |
| <a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/jdbc/kernel/PessimisticLockManager.html" target="_top"> |
| <code class="classname">o |
| rg.apache.openjpa.jdbc.kernel.PessimisticLockManager</code></a>, which |
| uses SELECT FOR UPDATE statements (or the database's equivalent) to lock the |
| database rows corresponding to locked objects. This lock |
| manager does not distinguish between read locks and write locks; all locks are |
| write locks. |
| </p><p> |
| The <code class="literal">pessimistic</code> LockManager can be configued to additionally |
| perform the version checking and incrementing behavior of the <code class="literal">version |
| </code> lock manager described below by setting its <code class="literal"> |
| VersionCheckOnReadLock</code> and <code class="literal">VersionUpdateOnWriteLock</code> |
| properties: |
| </p><pre class="programlisting"> |
| <property name="openjpa.LockManager" value="pessimistic(VersionCheckOnReadLock=true,VersionUpdateOnWriteLock=true)"/> |
| </pre></li><li><p> |
| <code class="literal">none</code>: An alias for the |
| <a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/kernel/NoneLockManager.html" target="_top"> |
| <code class="classname">org.apache.openjpa.kernel.NoneLockManager</code></a>, which |
| does not perform any locking at all. |
| </p></li><li><p> |
| <code class="literal">version</code>: An alias for the |
| <a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/kernel/VersionLockManager.html" target="_top"> |
| <code class="classname">org.apache.openjpa.kernel.VersionLockManager</code></a>. |
| This lock manager does not perform any exclusive locking, but instead ensures |
| read consistency by verifying that the version of all read-locked instances is |
| unchanged at the end of the transaction. Furthermore, a write lock will force an |
| increment to the version at the end of the transaction, even if the object is |
| not otherwise modified. This ensures read consistency with non-blocking |
| behavior. |
| </p><p> |
| This is the default <code class="literal">openjpa.LockManager</code> setting in JPA. |
| </p></li></ul></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p> |
| In order for the <code class="literal">version</code> lock manager to prevent the dirty |
| read phenomenon, the underlying data store's transaction isolation level must be |
| set to the equivalent of "read committed" or higher. |
| </p></div><div class="example"><a name="ref_guide_locking_disable"></a><p class="title"><b>Example 9.6. |
| Disabling Locking |
| </b></p><div class="example-contents"><pre class="programlisting"> |
| <property name="openjpa.LockManager" value="none"/> |
| </pre></div></div><br class="example-break"></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_locking_rules"></a>3.5. |
| Rules for Locking Behavior |
| </h3></div></div></div><a class="indexterm" name="d0e27702"></a><a class="indexterm" name="d0e27707"></a><p> |
| Advanced persistence concepts like lazy-loading and object uniquing create |
| several locking corner-cases. The rules below outline OpenJPA's implicit locking |
| behavior in these cases. |
| </p><div class="orderedlist"><ol type="1"><li><p> |
| When an object's state is first read within a transaction, the object is locked |
| at the fetch plan's current read lock level. Future reads of additional lazy |
| state for the object will use the same read lock level, even if the fetch plan's |
| level has changed. |
| </p></li><li><p> |
| When an object's state is first modified within a transaction, the object is |
| locked at the write lock level in effect when the object was first read, even if |
| the fetch plan's level has changed. If the object was not read previously, the |
| current write lock level is used. |
| </p></li><li><p> |
| When objects are accessed through a persistent relation field, the related |
| objects are loaded with the fetch plan's current lock levels, not the lock |
| levels of the object owning the field. |
| </p></li><li><p> |
| Whenever an object is accessed within a transaction, the object is re-locked at |
| the current read lock level. The current read and write lock levels become those |
| that the object "remembers" according to rules one and two above. |
| </p></li><li><p> |
| If you lock an object explicitly through the APIs demonstrated above, it is |
| re-locked at the specified level. This level also becomes both the read and |
| write level that the object "remembers" according to rules one and two above. |
| </p></li><li><p> |
| When an object is already locked at a given lock level, re-locking at a lower |
| level has no effect. Locks cannot be downgraded during a transaction. |
| </p></li></ol></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_locking_issues"></a>3.6. |
| Known Issues and Limitations |
| </h3></div></div></div><a class="indexterm" name="d0e27736"></a><p> |
| Due to performance concerns and database limitations, locking cannot be perfect. |
| You should be aware of the issues outlined in this section, as they may affect |
| your application. |
| </p><div class="itemizedlist"><ul type="disc"><li><p> |
| Typically, during optimistic transactions OpenJPA does not start an actual |
| database transaction until you flush or the optimistic transaction commits. This |
| allows for very long-lived transactions without consuming database resources. |
| When using the pessimistic lock manager, however, OpenJPA must begin a database |
| transaction whenever you decide to lock an object during an optimistic |
| transaction. This is because the pessimistic lock manager uses database locks, |
| and databases cannot lock rows without a transaction in progress. OpenJPA will |
| log an INFO message to the <code class="literal">openjpa.Runtime</code> logging channel |
| when it begins a datastore transaction just to lock an object. |
| </p></li><li><p> |
| In order to maintain reasonable performance levels when loading object state, |
| OpenJPA can only guarantee that an object is locked at the proper lock level |
| <span class="emphasis"><em>after</em></span> the state has been retrieved from the database. This |
| means that it is technically possible for another transaction to "sneak in" and |
| modify the database record after OpenJPA retrieves the state, but before it |
| locks the object. The only way to positively guarantee that the object is locked |
| and has the most recent state to refresh the object after locking it. |
| </p><p> |
| When using the pessimistic lock manager, the case above can only occur when |
| OpenJPA cannot issue the state-loading SELECT as a locking statement due to |
| database limitations. For example, some databases cannot lock SELECTs that use |
| joins. The pessimistic lock manager will log an INFO message to the <code class="literal"> |
| openjpa.Runtime</code> logging channel whenever it cannot lock the initial |
| SELECT due to database limitations. By paying attention to these log messages, |
| you can see where you might consider using an object refresh to guarantee that |
| you have the most recent state, or where you might rethink the way you load the |
| state in question to circumvent the database limitations that prevent OpenJPA |
| from issuing a locking SELECT in the first place. |
| </p></li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ref_guide_runtime_jpa.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ref_guide_runtime.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ref_guide_savepoints.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2. |
| JPA Extensions |
| </td><td width="20%" align="center"><a accesskey="h" href="manual.html">Home</a></td><td width="40%" align="right" valign="top"> 4. |
| Savepoints |
| </td></tr></table></div></body></html> |