Prev | Next | J2EETM Developer's Guide
Transactions |
The following pseudo-code illustrates the kind of fine-grained control you can obtain with bean-managed transactions. By checking various conditions, the pseudo-code decides whether to start and stop different transactions within the business method.
When coding a bean-managed transaction, you must decide whether to use JDBC or JTA transactions. The sections that follow discuss the techniques and merits of both approaches.begin transaction ... update table-a ... if (condition-x) commit transaction else if (condition-y) update table-b commit transaction else rollback transaction begin transaction update table-c commit transaction
commit
and rollback
methods of the javax.sql.Connection
interface. The beginning of a transaction is implicit. A transaction begins with the first SQL statement that follows the most recent commit
, rollback
, or connect
statement. (This rule is generally true, but may vary with DBMS vendor.)
The following code is from the WarehouseEJBexample, a session bean that uses the
Connection
interface's methods to delimit bean-managed transactions. The ship
method starts by invoking setAutoCommit
on the Connection
object con
. This invocation tells the DBMS not to automatically commit every SQL statement. Next, the ship
method calls routines that update the order_item
and inventory
database tables. If the updates succeed, the transaction is committed. But if an exception is thrown, the transaction is rolled back.
public void ship (String productId, String orderId, int quantity) { try { con.setAutoCommit(false); updateOrderItem(productId, orderId); updateInventory(productId, quantity); con.commit(); } catch (Exception ex) { try { con.rollback(); throw new EJBException("Transaction failed: " + ex.getMessage()); } catch (SQLException sqx) { throw new EJBException("Rollback failed: " + sqx.getMessage()); } } }
A JTA transaction is controlled by the J2EE transaction manager. You may want to use a JTA transaction because it can span updates to multiple databases from different vendors. A particular DBMS's transaction manager may not work with heterogenous databases. However, the J2EE transaction manager does have one limitation-- it does not support nested transactions. (It cannot start a transaction for an instance until the previous transaction has ended.)
To demarcate a JTA transaction, you invoke the begin
, commit
, and rollback
methods of the UserTransaction
interface. The following code, taken from the TellerEJB example program, demonstrates the
UserTransaction
methods. The begin
and commit
invocations delimit the updates to the database. If the updates fail, the code invokes the rollback
method and throws an EJBException
.
public void withdrawCash(double amount) { UserTransaction ut = context.getUserTransaction(); try { ut.begin(); updateChecking(amount); machineBalance -= amount; insertMachine(machineBalance); ut.commit(); } catch (Exception ex) { try { ut.rollback(); } catch (SystemException syex) { throw new EJBException ("Rollback failed: " + syex.getMessage()); } throw new EJBException ("Transaction failed: " + ex.getMessage()); } }
In a stateful session bean with a JTA transaction, the association between the bean instance and the transaction is retained across multiple client calls. Even if each business method called by the client opens and closes the database connection, the association is retained until the instance completes the transaction.
In a stateful session bean with a JDBC transaction, the JDBC connection retains the association between the bean instance and the transaction across multiple calls. If the connection is closed, the association is not retained.
getRollbackOnly
and setRollbackOnly
methods of the EJBContext
interface. These methods should be used only in container-managed transactions. For bean-managed transactions you invoke the the getStatus
and rollback
methods of the UserTransaction
interface.