mirror of https://github.com/apache/openjpa.git
440 lines
15 KiB
XML
440 lines
15 KiB
XML
<?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 entities 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>
|