TSTART (ObjectScript)
Synopsis
TSTART:pc
TS:pc
Argument
Argument | Description |
---|---|
pc | Optional — A postconditional expression. |
Description
TSTART marks the beginning of a transaction. Following TSTART, database operations are journaled to enable a subsequent TCOMMIT or TROLLBACK command.
TSTART increments the value of the $TLEVEL special variable. A $TLEVEL value of 0 indicates that no transaction is in effect. The first TSTART begins a transaction and increments $TLEVEL to 1. Subsequent TSTART commands can create nested transactions, further incrementing $TLEVEL.
Not all operations that occur within a transaction can be rolled back. For example, setting global variables within a transaction can be rolled back; setting local variables within a transaction cannot be rolled back. Refer to Using ObjectScript for Transaction Processing for further details.
By default, a lock issued within a transaction will be held until the end of the transaction, even if the lock is released within the transaction. This default can be overridden when setting the lock. Refer to the LOCK command for more details.
Argument
pc
An optional postconditional expression. InterSystems IRIS executes the TSTART command if the postconditional expression is true and does not execute the TSTART command if the postconditional expression is false. For further details, refer to Command Postconditional Expressions.
Nested Transactions
If you issue a TSTART within a transaction it begins a nested transaction. Issuing a TSTART increments the $TLEVEL value, indicating the number of levels of transaction nesting. You end a nested transaction by issuing either a TCOMMIT to commit the nested transaction, or a TROLLBACK 1 to roll back the nested transaction. Ending a nested transaction decrements the $TLEVEL value by 1.
-
Issuing a TROLLBACK 1 for a nested transaction rolls back changes made in that nested transaction and decrements $TLEVEL. You can issue a TROLLBACK to roll back the whole transaction, no matter how many levels of TSTART were issued.
-
Issuing a TCOMMIT for a nested transaction decrements $TLEVEL, but the actual commitment of the nested transaction is deferred. Changes made during a nested transaction are only irreversibly committed when the outermost transaction is committed; that is, when a TCOMMIT decrements the $TLEVEL value to 0.
You can use the GetImageJournalInfo()Opens in a new tab method of the %SYS.Journal.SystemOpens in a new tab class to search the journal file for TSTART commands, and thus identify open transactions. A TSTART writes either a “BT” (Begin Transaction) journal file record if $TLEVEL was zero, or a “BTL” (Begin Transaction with Level) journal file record if $TLEVEL was greater than 0.
The maximum number of levels of nested transactions is 255. Attempting to exceed this nesting levels limit results in a <TRANSACTION LEVEL> error.
SQL and Transactions
ObjectScript and SQL transaction commands are fully compatible and interchangeable, with the following exception:
ObjectScript TSTART and SQL START TRANSACTION both start a transaction if no transaction is current. However, START TRANSACTION does not support nested transactions. Therefore, if you need (or may need) nested transactions, it is preferable to start the transaction with TSTART. If you need compatibility with the SQL standard, use START TRANSACTION.
ObjectScript transaction processing provides limited support for nested transactions. SQL transaction processing supplies support for savepoints within transactions.
Examples
The following example uses a single-level transaction to transfer a random amount of money from one account to another. If the transfer amount is more than the available balance, the program rolls back the transaction:
SetupBankAccounts
SET num=12345
SET ^CHECKING(num,"balance")=500.99
SET ^SAVINGS(num,"balance")=100.22
IF $DATA(^NumberOfTransfers)=0 {SET ^NumberOfTransfers=0}
BankTransfer
WRITE "Before transfer:",!,"Checking=$",^CHECKING(num,"balance")," Savings=$",^SAVINGS(num,"balance"),!
// Transfer funds from one account to another
SET transfer=$RANDOM(1000)
WRITE "transfer amount $",transfer,!
DO CkToSav(num,transfer)
IF ok=1 {WRITE "sucessful transfer",!,"Number of transfers to date=",^NumberOfTransfers,!}
ELSE {WRITE "*** INSUFFICIENT FUNDS ***",!}
WRITE "After transfer:",!,"Checking=$",^CHECKING(num,"balance")," Savings=$",^SAVINGS(num,"balance"),!
RETURN
CkToSav(acct,amt)
TSTART
SET ^CHECKING(acct,"balance") = ^CHECKING(acct,"balance") - amt
SET ^SAVINGS(acct,"balance") = ^SAVINGS(acct,"balance") + amt
SET ^NumberOfTransfers=^NumberOfTransfers + 1
IF ^CHECKING(acct,"balance") > 0 {TCOMMIT SET ok=1 QUIT:ok}
ELSE {TROLLBACK SET ok=0 QUIT:ok}
The following examples use TSTART to create nested transactions. They show three scenarios for rollback of nested transactions:
Roll back the innermost transaction, commit the middle transaction, commit the outermost transaction:
KILL ^a,^b,^c
TSTART SET ^a=1 WRITE "tlevel=",$TLEVEL,!
TSTART SET ^b=2 WRITE "tlevel=",$TLEVEL,!
TSTART SET ^c=3 WRITE "tlevel=",$TLEVEL,!
TROLLBACK 1 WRITE "tlevel=",$TLEVEL,!
TCOMMIT WRITE "tlevel=",$TLEVEL,!
TCOMMIT WRITE "tlevel=",$TLEVEL,!
IF $DATA(^a) {WRITE "^a=",^a,!} ELSE {WRITE "^a is undefined",!}
IF $DATA(^b) {WRITE "^b=",^b,!} ELSE {WRITE "^b is undefined",!}
IF $DATA(^c) {WRITE "^c=",^c,!} ELSE {WRITE "^c is undefined",!}
Commit the innermost transaction, roll back the middle transaction, commit the outermost transaction:
KILL ^a,^b,^c
TSTART SET ^a=1 WRITE "tlevel=",$TLEVEL,!
TSTART SET ^b=2 WRITE "tlevel=",$TLEVEL,!
TSTART SET ^c=3 WRITE "tlevel=",$TLEVEL,!
TCOMMIT WRITE "tlevel=",$TLEVEL,!
TROLLBACK 1 WRITE "tlevel=",$TLEVEL,!
TCOMMIT WRITE "tlevel=",$TLEVEL,!
IF $DATA(^a) {WRITE "^a=",^a,!} ELSE {WRITE "^a is undefined",!}
IF $DATA(^b) {WRITE "^b=",^b,!} ELSE {WRITE "^b is undefined",!}
IF $DATA(^c) {WRITE "^c=",^c,!} ELSE {WRITE "^c is undefined",!}
Commit the innermost transaction, commit the middle transaction, roll back the outermost transaction:
KILL ^a,^b,^c
TSTART SET ^a=1 WRITE "tlevel=",$TLEVEL,!
TSTART SET ^b=2 WRITE "tlevel=",$TLEVEL,!
TSTART SET ^c=3 WRITE "tlevel=",$TLEVEL,!
TCOMMIT WRITE "tlevel=",$TLEVEL,!
TCOMMIT WRITE "tlevel=",$TLEVEL,!
TROLLBACK 1 WRITE "tlevel=",$TLEVEL,!
IF $DATA(^a) {WRITE "^a=",^a,!} ELSE {WRITE "^a is undefined",!}
IF $DATA(^b) {WRITE "^b=",^b,!} ELSE {WRITE "^b is undefined",!}
IF $DATA(^c) {WRITE "^c=",^c,!} ELSE {WRITE "^c is undefined",!}
Note that in this third case, TROLLBACK 1 and TROLLBACK would have the same result, because both would decrement $TLEVEL to 0.