Transactions and Locking
The Native SDK for Java provides transaction and locking methods that use the InterSystems IRIS transaction model, as described in the following sections:
-
Controlling Transactions — describes how transactions are started, nested, rolled back, and committed.
-
Concurrency Control — describes how to use the various lock methods.
DO NOT mix the Native SDK transaction model with the JDBC (java.sql) transaction model.
-
If you want to use only Native SDK commands within a transaction, you should always use Native SDK transaction methods.
-
If you want to use a mix of Native SDK and JDBC/SQL commands within a transaction, you should turn autoCommit OFF and then always use Native SDK transaction methods.
-
If you want to use only JDBC/SQL commands within a transaction, you can either always use SQL transaction methods, or turn autocommit OFF and then always use Native SDK transaction methods.
-
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 SDK model for transaction and concurrency control is based on ObjectScript methods, and is not interchangeable with the JDBC model. The Native SDK model must be used if your transactions include Native SDK method calls.
For more information on the ObjectScript transaction model, see “Transaction Processing” in Using ObjectScript.
The Native SDK for Java 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.
String globalName = "myGlobal";
irisjv.tStart();
// getTLevel() is 1: create myGlobal(1) = "firstValue"
irisjv.set("firstValue", globalName, irisjv.getTLevel());
irisjv.tStart();
// getTLevel() is 2: create myGlobal(2) = "secondValue"
irisjv.set("secondValue", globalName, irisjv.getTLevel());
irisjv.tStart();
// getTLevel() is 3: create myGlobal(3) = "thirdValue"
irisjv.set("thirdValue", globalName, irisjv.getTLevel());
System.out.println("Node values before rollback and commit:");
for (int ii=1;ii<4;ii++) {
System.out.print(globalName + "(" + ii + ") = ");
if (irisjv.isDefined(globalName,ii) > 1) System.out.println(irisjv.getString(globalName,ii));
else System.out.println("<valueless>");
}
// prints: Node values before rollback and commit:
// myGlobal(1) = firstValue
// myGlobal(2) = secondValue
// myGlobal(3) = thirdValue
irisjv.tRollbackOne();
irisjv.tRollbackOne(); // roll back 2 levels to getTLevel 1
irisjv.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 (irisjv.isDefined(globalName,ii) > 1) System.out.println(irisjv.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 SDK transaction model provides a set of locking methods that correspond to ObjectScript commands. These methods must not be used with the JDBC/SQL transaction model (see the warning at the beginning of this chapter for details).
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, or SE for shared and escalating. Default is empty string (exclusive and non-escalating).
-
timeout — number of seconds to wait when attempting to acquire the lock
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.
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:
-
“Transaction Processing” and “Lock Management” in Using ObjectScript
-
“Locking and Concurrency Control” in the Orientation Guide for Server-Side Programming
-
“LOCK” in the ObjectScript Reference