| 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.