PSE/PSE Pro for Java API User Guide

Working with Transactions

A transaction is a logical unit of work. It is a consistent and reliable portion of the execution of a program. In your code, you place calls to the PSE/PSE Pro API to mark the beginnings and ends of transactions. Initial access to a persistent object must always take place inside a transaction. Depending on how the transaction is committed, additional access to persistent objects might be possible.

Either the database is updated with all of a transaction's changes to persistent objects, or the database is not updated at all. If a failure occurs in the middle of a transaction or you decide to abort the transaction, the contents of the database remain unchanged.

Contents

This chapter discusses the following topics:

Starting a Transaction

Ending a Transaction

Determining If a Transaction Is in Progress

Determining Transaction Boundaries

Starting a Transaction

PSE/PSE Pro provides the Transaction class to represent a transaction. You should not make subclasses of this class.

Calling the begin() Method

To start a transaction, call the begin() method on the Transaction class. This returns an instance of Transaction and you can assign it to a variable. The method signature is

Method signature

public static Transaction begin(byte type)
The type of the transaction can be ObjectStore.READONLY or ObjectStore.UPDATE.

Example

Transaction tr = Transaction.begin(ObjectStore.UPDATE);
This example returns a Transaction object that represents the transaction just started. The result is stored in tr. This is an update transaction, which means that the application can modify database contents.

Modifying Objects in a Transaction

To modify persistent objects you must specify the transaction type to be ObjectStore.UPDATE. Also, the database must have been opened for update. Note that even if you open a database for read only, PSE/PSE Pro allows you to start an update transaction. An application does not receive an exception until it tries to modify persistent objects inside the read-only database.

If you try to modify persistent data in a read-only transaction, PSE/PSE Pro throws UpdateReadOnlyException.

Update and Read-Only Transactions

You can start a transaction for READONLY or for UPDATE. The only difference between the two types is that PSE/PSE Pro performs additional checks during a transaction and when you commit a transaction that you started for read only. These checks ensure that changes are not saved in the database if they were made in a read-only transaction.

Transactions and Sessions

A session can have only one active transaction.

PSE

PSE allows one active session. With COM.odi.useDatabaseLocking set to true, separate processes can simultaneously have separate read-only transactions against the same database. Also, separate processes can simultaneously have separate update transactions against different databases. Cooperating threads can update the same database.

PSE Pro

PSE Pro allows multiple sessions. If COM.odi.useDatabaseLocking is set to true, separate processes and noncooperating threads (separate sessions) can simultaneously have separate read-only transactions against the same database. Also, separate processes and noncooperating threads can simultaneously have separate update transactions against different databases; each process or thread (session) must update a different database. Cooperating threads can update the same database.

Transaction Already in Progress

Nested transactions are not allowed. If you try to start a transaction when a transaction for the current thread is already in progress, PSE/PSE Pro throws TransactionInProgressException.

Obtaining transaction objects

An application can obtain the transaction object for the current thread by calling the static current() method on the Transaction class. The method signature is

public static Transaction current()
This method returns the transaction object associated with the current thread. For example:

Transaction.current().commit()
This example commits the current transaction. If no transaction is in progress, current() throws NoTransactionInProgressException.

Ending a Transaction

When transactions terminate successfully, they commit, and their changes to persistent objects are saved in the database. When transactions terminate unsuccessfully, they abort, and their changes to persistent objects are discarded.

Committing Transactions

PSE/PSE Pro provides the Transaction.commit() method for successfully ending a transaction. When an application commits a transaction, PSE/PSE Pro

Caution

You must ensure that an object never refers to an object that belongs to a different session. This is crucial because transitive persistence must never reach an object that belongs to another session.

To commit a transaction and make the state of persistent objects stale, call the commit() method. The method signature is

public void commit()
For example:

tr.commit();
To commit a transaction and be flexible about the state of persistent objects after the transaction, call the commit(retain) method on the transaction. The values you can specify for retain are described in Committing Transactions to Save Modifications and Set Object State. The method signature is

public void commit(int retain)
The example below commits the transaction and specifies that the contents of the active persistent objects should remain available to be read.

tr.commit(ObjectStore.RETAIN_READONLY);

What Can Cause a Transaction Commit to Fail?

When trying to commit a transaction, if PSE/PSE Pro encounters any of the situations listed below, it causes the transaction commit to fail . When PSE/PSE Pro aborts a transaction commit, it throws AbortException.

Aborting Transactions

PSE/PSE Pro provides theTransaction.abort() method for unsuccessfully ending a transaction. When an application aborts a transaction, PSE/PSE Pro

Only the state of the database is rolled back. The state of transient objects is not undone automatically. Applications are responsible for undoing the states of transient objects. Any form of output that occurred before the abort cannot be undone.

If an application fails during a transaction, when you restart the application the database is as it was before the transaction started. If an application fails during a transaction commit, when you restart the application the database is either as it was before the transaction that was being committed or the database reflects all the transaction's changes. This depends on how far along in the commit process the application was when it terminated. In any case, either all or none of the transaction's changes are in the database.

To abort a transaction and set the state of persistent objects to the state specified by Transaction.setDefaultAbortRetain(), call the abort() method. The default state is stale. The method signature is

public void abort()
For example:

tr.abort();
To abort a transaction and specify a particular state for persistent objects after the transaction, call the abort(retain) method on the transaction. The values you can specify for retain are described in Specifying a Particular State for Persistent Objects. The method signature is

public void abort(int retain)
The example below aborts the transaction and specifies that the contents of the active persistent objects should remain available to be read.

tr.abort(ObjectStore.RETAIN_READONLY);

Determining If a Transaction Is in Progress

To determine whether or not there is a transaction in progress for the current thread, call the inTransaction() method on the transaction. The method signature is

public static boolean inTransaction()
This method returns true if there is a transaction in progress for the current thread. Otherwise, it returns false.

Determining Transaction Boundaries

When determining whether or not to commit a transaction, consider database state and interdependencies among cooperating threads.

Inconsistent Database State

You should not commit a transaction if the database is in a logically inconsistent state. A database is considered to be in an inconsistent state if at that moment a just-started transaction would encounter problems upon viewing the current state of the data.

Consider your database to be something that moves from one consistent state to another. You should only commit a transaction when the state is consistent. When is a database consistent? When the answer to this question is yes: If you start your application at this very moment, is the database completely usable exactly the way it is now?

For example, suppose your database contains information about married couples. Couples refer to one another through a spouse field. At a particular moment, suppose a person in the database refers to another person in the database through its spouse field but that spouse does not refer to the first person. At that moment, the database is in an inconsistent state.

When the database state is consistent you might decide not to commit the transaction. However, if you do not commit you risk losing changes if PSE/PSE Pro aborts the transaction. You should always commit changes before you inform a user or some other interface that a particular task was accomplished.

Multiple Cooperating Threads

If your application uses cooperating threads, you must take this into account when determining when to commit transactions. For example, you do not want to create a situation where one thread commits a transaction while another thread is accessing persistent objects. The commit() method makes all persistent objects stale for all cooperating threads. You must coordinate the Transaction.begin() and Transaction.commit() operations among cooperating threads.

Synchronizing threads is like having a joint checking account. Suppose the amount in the checking account is $100.00. Your partner writes a check for $50.00. Then you try to cash a check for $75,00. This does not work. It does not matter that it was your partner and not you that wrote the check for $50.00. You and your partner have to cooperate.



[previous] [next]

doc@odi.com
Copyright © 1997 Object Design, Inc. All rights reserved.

Updated: 05/13/97 12:17:57