blob: c444311675c20bec5d5ecc56a8c9970fa0e51c1d [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<chapter id="jpa_overview_trans">
<title>
Transaction
</title>
<indexterm zone="jpa_overview_trans">
<primary>
transactions
</primary>
<seealso>
Transaction
</seealso>
</indexterm>
<para>
Transactions are critical to maintaining data integrity. They are used to group
operations into units of work that act in an all-or-nothing fashion.
Transactions have the following qualities:
</para>
<itemizedlist>
<listitem>
<para>
<indexterm>
<primary>
atomicity
</primary>
<seealso>
transactions
</seealso>
</indexterm>
<indexterm>
<primary>
transactions
</primary>
<secondary>
atomicity
</secondary>
</indexterm>
<emphasis>Atomicity</emphasis>. Atomicity refers to the all-or-nothing property
of transactions. Either every data update in the transaction completes
successfully, or they all fail, leaving the datastore in its original state. A
transaction cannot be only partially successful.
</para>
</listitem>
<listitem>
<para>
<indexterm>
<primary>
consistency
</primary>
<seealso>
transactions
</seealso>
</indexterm>
<indexterm>
<primary>
transactions
</primary>
<secondary>
consistency
</secondary>
</indexterm>
<emphasis>Consistency</emphasis>. Each transaction takes the datastore from one
consistent state to another consistent state.
</para>
</listitem>
<listitem>
<para>
<indexterm>
<primary>
isolation
</primary>
<seealso>
transactions
</seealso>
</indexterm>
<indexterm>
<primary>
transactions
</primary>
<secondary>
isolation
</secondary>
</indexterm>
<emphasis>Isolation</emphasis>. Transactions are isolated from each other. When
you are reading persistent data in one transaction, you cannot "see" the changes
that are being made to that data in other transactions. Similarly, the updates
you make in one transaction cannot conflict with updates made in concurrent
transactions. The form of conflict resolution employed depends on whether you
are using pessimistic or optimistic transactions. Both types are described later
in this chapter.
</para>
</listitem>
<listitem>
<para>
<indexterm>
<primary>
durability
</primary>
<seealso>
transactions
</seealso>
</indexterm>
<indexterm>
<primary>
transactions
</primary>
<secondary>
durability
</secondary>
</indexterm>
<emphasis>Durability</emphasis>. The effects of successful transactions are
durable; the updates made to persistent data last for the lifetime of the
datastore.
</para>
</listitem>
</itemizedlist>
<para>
<indexterm>
<primary>
ACID
</primary>
<seealso>
transactions
</seealso>
</indexterm>
<indexterm>
<primary>
transactions
</primary>
<secondary>
ACID
</secondary>
</indexterm>
Together, these qualities are called the ACID properties of transactions. To
understand why these properties are so important to maintaining data integrity,
consider the following example:
</para>
<para>
Suppose you create an application to manage bank accounts. The application
includes a method to transfer funds from one user to another, and it looks
something like this:
</para>
<programlisting>
public void transferFunds(User from, User to, double amnt) {
from.decrementAccount(amnt);
to.incrementAccount(amnt);
}
</programlisting>
<para>
Now suppose that user Alice wants to transfer 100 dollars to user Bob. No
problem; you simply invoke your <methodname>transferFunds</methodname> method,
supplying Alice in the <literal>from</literal> parameter, Bob in the <literal>
to</literal> parameter, and <literal>100.00</literal> as the <literal>amnt
</literal>. The first line of the method is executed, and 100 dollars is
subtracted from Alice's account. But then, something goes wrong. An unexpected
exception occurs, or the hardware fails, and your method never completes.
</para>
<para>
You are left with a situation in which the 100 dollars has simply disappeared.
Thanks to the first line of your method, it is no longer in Alice's account, and
yet it was never transferred to Bob's account either. The datastore is in an
inconsistent state.
</para>
<para>
The importance of transactions should now be clear. If the two lines of the
<methodname>transferFunds</methodname> method had been placed together in a
transaction, it would be impossible for only the first line to succeed. Either
the funds would be transferred properly or they would not be transferred at all,
and an exception would be thrown. Money could never vanish into thin air, and
the data store could never get into an inconsistent state.
</para>
<section id="jpa_overview_trans_types">
<title>
Transaction Types
</title>
<indexterm zone="jpa_overview_trans_types">
<primary>
transactions
</primary>
<secondary>
types
</secondary>
</indexterm>
<para>
There are two major types of transactions: pessimistic transactions and
optimistic transactions. Each type has both advantages and disadvantages.
</para>
<para>
<indexterm>
<primary>
transactions
</primary>
<secondary>
pessimistic
</secondary>
</indexterm>
<indexterm>
<primary>
pessimistic transactions
</primary>
<see>
transactions, pessimistic
</see>
</indexterm>
<indexterm>
<primary>
deadlock
</primary>
<seealso>
transactions
</seealso>
</indexterm>
Pessimistic transactions generally lock the datastore records they act on,
preventing other concurrent transactions from using the same data. This avoids
conflicts between transactions, but consumes database resources. Additionally,
locking records can result in <emphasis>deadlock</emphasis>, a situation in
which two transactions are both waiting for the other to release its locks
before completing. The results of a deadlock are datastore-dependent; usually
one transaction is forcefully rolled back after some specified timeout interval,
and an exception is thrown.
</para>
<para>
<indexterm>
<primary>
transactions
</primary>
<secondary>
datastore
</secondary>
</indexterm>
<indexterm>
<primary>
datastore transactions
</primary>
<see>
transactions, datastore
</see>
</indexterm>
This document will often use the term <emphasis>datastore</emphasis> transaction
in place of <emphasis>pessimistic</emphasis> transaction. This is to acknowledge
that some datastores do not support pessimistic semantics, and that the exact
meaning of a non-optimistic JPA transaction is dependent on the datastore. Most
of the time, a datastore transaction is equivalent to a pessimistic transaction.
</para>
<para>
<indexterm>
<primary>
transactions
</primary>
<secondary>
optimistic
</secondary>
</indexterm>
<indexterm>
<primary>
optimistic transactions
</primary>
<see>
transactions, optimistic
</see>
</indexterm>
Optimistic transactions consume less resources than pessimistic/datastore
transactions, but only at the expense of reliability. Because optimistic
transactions do not lock datastore records, two transactions might change the
same persistent information at the same time, and the conflict will not be
detected until the second transaction attempts to flush or commit. At this time,
the second transaction will realize that another transaction has concurrently
modified the same records (usually through a timestamp or versioning system),
and will throw an appropriate exception. Note that optimistic transactions still
maintain data integrity; they are simply more likely to fail in heavily
concurrent situations.
</para>
<para>
Despite their drawbacks, optimistic transactions are the best choice for most
applications. They offer better performance, better scalability, and lower risk
of hanging due to deadlock.
</para>
<note>
<para>
OpenJPA uses optimistic semantics by default, but supports both optimistic and
datastore transactions. OpenJPA also offers advanced locking and versioning APIs
for fine-grained control over database resource allocation and object
versioning. See <xref linkend="ref_guide_locking"/> of the Reference Guide for
details on locking. <xref linkend="jpa_overview_meta_version"/>
of this document covers standard object versioning, while
<xref linkend="ref_guide_mapping_jpa"/> of the Reference Guide discusses
additional versioning strategies available in OpenJPA.
</para>
</note>
</section>
<section id="jpa_overview_trans_local">
<title>
The EntityTransaction Interface
</title>
<indexterm zone="jpa_overview_trans_local">
<primary>
Transaction
</primary>
<seealso>
transactions
</seealso>
</indexterm>
<mediaobject>
<imageobject>
<!-- PNG image data, 193 x 157 (see README) -->
<imagedata fileref="img/jpa-transaction.png" width="129px"/>
</imageobject>
</mediaobject>
<para>
JPA integrates with your container's <emphasis>managed</emphasis> transactions,
allowing you to use the container's declarative transaction demarcation and its
Java Transaction API (JTA) implementation for transaction management. Outside of
a container, though, you must demarcate transactions manually through JPA. The
<classname>EntityTransaction</classname> interface controls unmanaged
transactions in JPA.
</para>
<programlisting>
public void begin();
public void commit();
public void rollback();
</programlisting>
<para>
<indexterm>
<primary>
Transaction
</primary>
<secondary>
demarcation
</secondary>
</indexterm>
<indexterm>
<primary>
transactions
</primary>
<secondary>
demarcating
</secondary>
</indexterm>
<indexterm>
<primary>
Transaction
</primary>
<secondary>
begin
</secondary>
</indexterm>
<indexterm>
<primary>
Transaction
</primary>
<secondary>
commit
</secondary>
</indexterm>
<indexterm>
<primary>
Transaction
</primary>
<secondary>
rollback
</secondary>
</indexterm>
The <methodname>begin</methodname>, <methodname>commit</methodname>, and
<methodname>rollback</methodname> methods demarcate transaction boundaries. The
methods should be self-explanatory: <methodname>begin</methodname> starts a
transaction, <methodname>commit</methodname> attempts to commit the
transaction's changes to the datastore, and <methodname>rollback</methodname>
aborts the transaction, in which case the datastore is "rolled back" to its
previous state. JPA implementations will automatically roll back transactions if
any exception is thrown during the commit process.
</para>
<para>
Unless you are using an extended persistence context, committing or rolling back
also ends the persistence context. All managed entites will be detached from the
<classname>EntityManager</classname>.
</para>
<programlisting>
public boolean isActive();
</programlisting>
<para>
<indexterm>
<primary>
Transaction
</primary>
<secondary>
isActive
</secondary>
</indexterm>
Finally, the <methodname>isActive</methodname> method returns <literal>true
</literal> if the transaction is in progress (<methodname>begin</methodname>
has been called more recently than <methodname>commit</methodname> or
<methodname>rollback</methodname>), and <literal>false</literal> otherwise.
</para>
<example id="jpa_overview_trans_group">
<title>
Grouping Operations with Transactions
</title>
<programlisting>
public void transferFunds(EntityManager em, User from, User to, double amnt) {
// note: it would be better practice to move the transaction demarcation
// code out of this method, but for the purposes of example...
Transaction trans = em.getTransaction();
trans.begin();
try
{
from.decrementAccount(amnt);
to.incrementAccount(amnt);
trans.commit();
}
catch (RuntimeException re)
{
if (trans.isActive())
trans.rollback(); // or could attempt to fix error and retry
throw re;
}
}
</programlisting>
</example>
</section>
</chapter>