For a general introduction to transaction-oriented programming with Tamino, see also the document Transactions Guide.
When opening a TaminoConnection
, you need to
specify how commands are to be handled by the Tamino XML
Server by using the TaminoConnectionMode enumeration. The
enumeration has the following values:
AutoCommit;
LocalTransaction;
GlobalTransaction.
These values specify the scope of a command's transaction.
Additionally, the behavior within a transaction can be specified in more detail. For more information, refer to these sections:
This document comprises the following sections:
Note:
On multithreaded transaction usage: It is the user's responsibility
to ensure that multiple threads do not attempt to execute transactional
commands simultaneously. In other words, the operations
BeginTransaction
, Commit
and
Rollback
must not be performed on the same
TaminoConnection
or
TaminoTransaction
by two or more threads
simultaneously.
Each command runs within the scope of a single transaction. The result of each command is automatically committed by the Tamino XML Server. This means that each command affects the database immediately after it has been successfully processed.
... // open connection in AutoCommit mode connection.Open(TaminoConnectionMode.AutoCommit); // delete some document TaminoResponse response = command.Delete(someDocumentUri); Trace.Assert(response.ReturnValue == "0", response.ErrorText); // if we get here the delete worked - oops can't undo the delete now! // close the connection connection.Close(); ...
The application marks the beginning and end of a transaction. All commands executed between the beginning and end of the transaction run within the scope of the transaction. To complete a transaction, the application can decide whether to commit or rollback all the changes made by all the commands. This allows the application to group a set of commands and either commit either all the changes or none of them. Using local transactions you can only group commands associated with the same Tamino database.
The following sample shows how to delete a document and then commit the delete. After being committed, the changes to the database cannot be rolled back!
... // open connection in LocalTransaction mode connection.Open(TaminoConnectionMode.LocalTransaction); // begin transaction TaminoTransaction tx = connection.BeginTransaction(); // delete some document TaminoResponse response = command.Delete(someDocumentUri); Trace.Assert(response.ReturnValue == "0", response.ErrorText); // if we get here the delete worked - could still undo the delete if need be // commit the preceding commands [in this case the Delete] tx.Commit(); // oops can't change our mind now! // close the connection connection.Close(); ...
The following sample shows how to delete a document and then rollback
the delete. This undoes the delete of the document, leaving the database in the
same state as it was in before the method
BeginTransaction
was called (assuming that this
program is the only program accessing the database).
... // open connection in LocalTransaction mode connection.Open(TaminoConnectionMode.LocalTransaction); // begin transaction TaminoTransaction tx = connection.BeginTransaction(); // delete some document TaminoResponse response = command.Delete(someDocumentUri); Trace.Assert(response.ReturnValue == "0", response.ErrorText); // if we get here the delete worked - could still undo the delete if need be // we do undo the Delete by doing a Rollback // rollback the preceding commands [in this case the Delete] tx.Rollback(); // phew - undid the Delete! // close the connection connection.Close(); ...
You can use global/distributed transactions to group commands associated with different databases. All the commands run within the scope of a distributed transaction. For a general introduction to distributed transactions in .NET, see ms-help://MS.NETFrameworkSDK/cpguidenf/html/cpconprocessingtransactions.htm.
To participate in a distributed transaction, the Tamino XML Server needs to know the transaction ID. The transaction ID of the currently-active distributed transaction can either be determined automatically by the Tamino API for .NET, or it can be explicitly specified by the application. In either case, the transaction ID is communicated to the Tamino XML Server.
If the transaction ID is to be determined automatically, then the .NET
Framework property
System.EnterpriseServices.ContextUtil.Transaction
must specify a distributed transaction that implements the Microsoft COM+
interface ITipTransaction
. This would be satisfied by a
.NET application running within the MS/DTC (Microsoft's Distributed Transaction
Monitor, which can coordinate commits/rollbacks in different databases)
transactional environment with the application specifying that it "Requires
Transaction" using the System.EnterpriseServices.TransactionAttribute. Note
that the TaminoConnection.Open
method must
execute within the context of the distributed transaction. The
TaminoConnection.Close
method may not be used
within an automatically-determined distributed transaction.
A TaminoConnection
used in GlobalTransactionMode
must not be closed if the transaction was an automatically-created transaction
(as opposed to a user-created global transaction). An attempt to close such a
connection would result in the Tamino server throwing an exception.
The following sample shows the code needed to use an automatically-determined transaction:
... // method/application with the .NET attribute // [TransactionAttribute(TransactionOption.Required)] // open connection in GlobalTransaction mode connection.Open(TaminoConnectionMode.GlobalTransaction); // insert a document TaminoResponse response = command.Insert(tamDoc); Trace.Assert(response.ReturnValue == "0", response.ErrorText); // do NOT close the connection ...
Instead of using transactional attributes, the distributed transaction
can also be explicitly under the control of the application. If it wishes to
perform Tamino operations in the context of this transaction, then it must
supply the transaction ID to Tamino via the
TaminoConnection.Open
method invocation. The
TaminoConnection.Close
method may be used after the
distributed transaction has been terminated.
... // user starts distributed transaction in some manner // obtain transaction id as TIP URL TaminoTxId txId = new TaminoTxId(tipUrl); // open the connection in GlobalTransaction mode connection.Open(txId); // insert a document TaminoResponse response = command.Insert(tamDoc); Trace.Assert(response.ReturnValue == "0", response.ErrorText); // user terminates distributed transaction in some manner // safe to close connection connection.Close(); ...
To ensure consistency, Tamino provides a sophisticated locking concept. For detailed information regarding the Tamino locking concept, please refer to the Tamino XML Server documentation. The application can specify the locking strategy to be applied for commands within transactions. The application can specify the locks at three different granularities within the API. The granularities, in order from most specific to least specific, are:
a single command within a single transaction;
all commands within a particular transaction;
all commands within all transactions of a connection.
The most specific settings take precedence over the least specific settings.
The locking strategy for the command can be specified by setting the
individual TaminoCommand
properties: IsolationLevel,
LockMode and Lockwait. If these properties are set to anything other than their
default values, then the requested lock value is applied to the next command.
It also applies to subsequent commands until the lock value is reset to its
default value by the application. Note that setting the
IsolationLevel
property per command is only
allowed for connections in AutoCommit mode.
... connection.Open(TaminoConnectionMode.AutoCommit); command.Lockwait = TaminoLockwait.No; TaminoQueryResponse qr = command.Query(query); command.Lockwait = TaminoLockwait.Default; ...
If no lock values are set in AutoCommit mode, then the default lock values are automatically applied by the Tamino XML Server itself.
You can specify the locking strategy for all the commands within a
specific transaction This is done by setting the lock values on the
TaminoConnection.BeginTransaction
invocation. This
applies the same lock values to all the commands executed within the
transaction.
... connection.Open(TaminoConnectionMode.LocalTransaction); TaminoTransaction tx = connection.BeginTransaction(TaminoIsolationLevel.Default, TaminoLockMode.Protected, TaminoLockwait.Yes); command.Query(query); command.Delete(uri); tx.Commit(); ...
If no lock values are set in LocalTransaction mode, then the default lock values are automatically applied by the Tamino XML Server itself.
You can specify the locking strategy for all the commands for a
connection. This is achieved by setting the lock values on the
TaminoConnection.Open
invocation. This causes all the
commands executed on the connection to have the same lock values applied.
... connection.Open(TaminoConnectionMode.LocalTransaction, TaminoIsolationLevel.Default, TaminoLockMode.Unprotected, TaminoLockwait.Default); TaminoTransaction tx = connection.BeginTransaction(); command.Query(query); tx.Commit(); ...
As noted above under the precedence rules, it is possible for a subsequent BeginTransaction invocation to provide a different set of lock values that would apply to that particular transaction.
You can set the timeouts that the Tamino Server applies to transactions
on a connection-by-connection basis. You specify timeout intervals by passing
in an instance of TaminoPreference
when creating the
instance of TaminoConnection
.
TaminoPreference
has two fields that allow you
to specify the transaction timeouts:
Specifies the maximum time interval in seconds between Commit/Rollback calls.
Specifies the maximum time interval in seconds between database operations.
By default, the Tamino Server uses database-specific values. You can use the Tamino Manager to view and modify these values.
... // create suitable preferences TaminoPreference preference = new TaminoPreference(); preference.TransactionTimeout = 60; preference.NonActivityTimeout = 30; // create connection TaminoConnection connection = new TaminoConnection(uri, preference); // open connection in LocalTransaction mode connection.Open(TaminoConnectionMode.LocalTransaction); // begin transaction TaminoTransaction tx = connection.BeginTransaction(); // do commands + Rollback/Commit operations with specified timeouts applied // close the connection connection.Close();