Previous section   Next section

Transactions and Locking

The Native API for Java offers an alternative to the standard java.sql transaction model. The Native API transaction model is based on ObjectScript transaction and locking methods, and is not interchangeable with the JDBC model. The Native API model must be used if your transactions include Native API method calls.
The following topics are discussed in this chapter:
Important:
Never Mix Transaction Models
NEVER mix the Native API transaction model with the JDBC (java.sql) transaction model.
  • Always use the Native API transaction model if your transaction will include any of the Native API methods described in this book.
  • Native API transactions can also include any JDBC/SQL methods other than transaction methods.
  • If you use only JDBC/SQL commands within a transaction, you can use either model.
  • Although you can use both models in the same application, you must take care never to start a transaction in one model while a transaction is still running in the other model.

Controlling Transactions

The methods described here are alternatives to the standard JDBC transaction model. The Native API model for transaction and concurrency control is based on ObjectScript methods, and is not interchangeable with the JDBC model. The Native API model must be used if your transactions include Native API method calls.
For more information on the ObjectScript transaction model, see “Transaction Processing” in Using ObjectScript.
The Native API provides the following methods to control transactions:
  • IRIS.tCommit() — commits one level of transaction.
  • IRIS.tStart() — starts a transaction (which may be a nested transaction).
  • IRIS.getTLevel() — returns an int value indicating the current transaction level (0 if not in a transaction).
  • IRIS.tRollback() — rolls back all open transactions in the session.
  • IRIS.tRollbackOne() — rolls back the current level transaction only. If this is a nested transaction, any higher-level transactions will not be rolled back.
The following example starts three levels of nested transaction, setting the value of a different node in each transaction level. All three nodes are printed to prove that they have values. The example then rolls back the second and third levels and commits the first level. All three nodes are printed again to prove that only the first node still has a value.
Controlling Transactions: Using three levels of nested transaction
  String globalName = "myGlobal";
  iris.tStart();

  // getTLevel() is 1: create myGlobal(1) = "firstValue"
  iris.set("firstValue", globalName, iris.getTLevel());

  iris.tStart();
  // getTLevel() is 2: create myGlobal(2) = "secondValue"
  iris.set("secondValue", globalName, iris.getTLevel());

  iris.tStart();
  // getTLevel() is 3: create myGlobal(3) = "thirdValue"
  iris.set("thirdValue", globalName, iris.getTLevel());

  System.out.println("Node values before rollback and commit:");
  for (int ii=1;ii<4;ii++) {
    System.out.print(globalName + "(" + ii + ") = ");
    if (iris.isDefined(globalName,ii) > 1) System.out.println(iris.getString(globalName,ii));
    else System.out.println("<valueless>");
  }
// prints: Node values before rollback and commit:
//         myGlobal(1) = firstValue
//         myGlobal(2) = secondValue
//         myGlobal(3) = thirdValue

  iris.tRollbackOne();
  iris.tRollbackOne();  // roll back 2 levels to getTLevel 1
  iris.tCommit();  // getTLevel() after commit will be 0
  System.out.println("Node values after the transaction is committed:");
  for (int ii=1;ii<4;ii++) {
    System.out.print(globalName + "(" + ii + ") = ");
    if (iris.isDefined(globalName,ii) > 1) System.out.println(iris.getString(globalName,ii));
    else System.out.println("<valueless>");
  }
// prints: Node values after the transaction is committed:
//         myGlobal(1) = firstValue
//         myGlobal(2) = <valueless>
//         myGlobal(3) = <valueless>

Concurrency Control

Concurrency control is a vital feature of multi-process systems such as InterSystems IRIS. It provides the ability to lock specific elements of data, preventing the corruption that would result from different processes changing the same element at the same time. The Native API transaction model provides a set of locking methods that correspond to ObjectScript commands.
The following methods of class IRIS are used to acquire and release locks. Both methods take a lockMode argument to specify whether the lock is shared or exclusive:
   lock (String lockMode, Integer timeout, String globalName, String...subscripts)
   unlock (String lockMode, String globalName, String...subscripts)
  • IRIS.lock() — Takes lockMode, timeout, globalName, and subscripts arguments, and locks the node. The lockMode argument specifies whether any previously held locks should be released. This method will time out after a predefined interval if the lock cannot be acquired.
  • IRIS.unlock() — Takes lockMode, globalName, and subscripts arguments, and releases the lock on a node.
The following argument values can be used:
  • lockMode — combination of the following chars, S for shared lock, E for escalating lock, default is empty string (exclusive and non-escalating)
  • timeout — amount to wait to acquire the lock in seconds
Note:
You can use the Management Portal to examine locks. Go to System Operation > Locks to see a list of the locked items on your system.
There are two ways to release all currently held locks:
  • IRIS.releaseAllLocks() — releases all locks currently held by this connection.
  • When the close() method of the connection object is called, it releases all locks and other connection resources.
Tip:
A detailed discussion of concurrency control is beyond the scope of this book. See the following books and articles for more information on this subject:
Previous section   Next section