Transaction
Overview
You can use transactions to manage multiple opertions. Typically you would put them in a transactional process as follows:
TransactionManager tm = TransactionManagerUtil.getTransactionManager(); try{ tm.beginTransaction();//start transaction explicitly withdraw(...);//operation 1 deposit(...); //operation 2 tm.commitTransaction(); } catch (Exception ex) { tm.rollbackTransaction(); } finally { tm.releaseResources(); }
Line tm.beginTransaction() starts a new transaction by using a default transaction type. If all operations are successful, you use tm.commitTransaction() to make the changes permanent. However, if one operation fails, you rollback the changes by using tm.rollbackTransaction(). Finally you want to release any resources, such as a database connection, held by the transaction by calling tm.releaseResources().
Choosing a Transaction Type
Scooter supports three transaction types:
- JDBC - using Database Connection to manage transaction
- JTA - using UserTransaction
- CMT - using Container's transaction manager
When you start a transaction, you can use one of the above three transaction types as follows:
tm.beginTransaction(type);
If you do not choose a transaction type, the transaction type will be JDBC by default. You can change this default transaction type by modifying the default.transaction.type property in database.properties file.
Using Transactions
There are many ways to use transactions in code. Here are some examples.
Example 1: Start a new transaction explicitly
SqlService sqlSvc = SqlServiceConfig.getSqlService(); try{ sqlSvc.beginTransaction();//start transaction explicitly sqlSvc.update(...); sqlSvc.update(...); sqlSvc.commitTransaction(); } catch (Exception ex) { sqlSvc.rollbackTransaction(); } finally { sqlSvc.releaseResources(); }
Example 2: Start a new transaction explicitly by using TransactionManager
/* * SQL Data Express example */ SqlService sqlSvc = SqlServiceConfig.getSqlService(); TransactionManager tm = TransactionManagerUtil.getTransactionManager(); try{ //start transaction explicitly tm.beginTransaction(); sqlSvc.update(...); sqlSvc.update(...); tm.commitTransaction(); } catch (Exception ex) { tm.rollbackTransaction(); } finally { tm.releaseResources(); } |
/* * Active Record example */ Acctount acctF = Account.findById(1001); Acctount acctT = Account.findById(1002); TransactionManager tm = TransactionManagerUtil.getTransactionManager(); try{ //start transaction explicitly tm.beginTransaction(); acctF.withdraw(10); acctT.deposit(10); tm.commitTransaction(); } catch (Exception ex) { tm.rollbackTransaction(); } finally { tm.releaseResources(); } |
Example 3: Start a new transaction explicitly by using UserTransaction
/* * SQL Data Express example */ SqlService sqlSvc = SqlServiceConfig.getSqlService(); UserTransaction utx = ...; try{ //start transaction explicitly utx.beginTransaction(); //operate in the existing utx transaction sqlSvc.update(...); sqlSvc.update(...); utx.commitTransaction(); } catch (Exception ex) { utx.rollbackTransaction(); } |
/* * Active Record example */ Acctount acctF = Account.findById(1001); Acctount acctT = Account.findById(1002); UserTransaction utx = ...; try{ //start transaction explicitly utx.beginTransaction(); //operate in the existing utx transaction acctF.withdraw(10); acctT.deposit(10); utx.commitTransaction(); } catch (Exception ex) { utx.rollbackTransaction(); } |
Implicit Transaction
In each of the three examples above, a new transaction is started. But sometimes you do not want to start a new transaction when there is already a transaction in the calling context. Implicit transaction provides this flexibility.
Implicit transaction starts a new transaction only when there is no transaction in the calling context. When there is an existing transaction in the calling context, implicit transaction simply delegates to this existing transaction.
Simply put, Scooter's implicit transaction is like EJB's TRANSACTION_REQUIRED type of transaction.
Example 4: Start a new transaction automatically when a service method is called.
sqlSvc.update(..); //automatically start a new transaction. sqlSvc.insert(..); //automatically start another transaction.
Example 5: Start a new implicit transaction by using ImplicitTransactionManager
//We use implicit transaction here instead of regular transaction because //we expect transfer() be used in other transaction context. public void transfer(...) { ImplicitTransactionManager itm = TransactionManagerUtil.getImplicitTransactionManager(); try{ itm.beginTransactionImplicit();//start transaction implicitly sqlSvc.withdraw(..); sqlSvc.deposit(..); itm.commitTransactionImplicit(); } catch (Exception ex) { itm.rollbackTransactionImplicit(); } finally { itm.releaseResourcesImplicit(); } }