Best Practices - Data Transaction Handling
The purpose of this document is to provide best practices for data transaction handling.
Main principles
Managing database transactions requires that you know the main principles associated with this function in the SAFE X3 engine. The main principles are as follows:
- A database transaction groups a set of consistent updates performed in a database. They are either completely applied to the data, or not at all.
- During a database transaction, the database layer locks the resources. Therefore, a transaction must be short, and it must never be interrupted by a user interaction.
- A database transaction starts with Trbegin, and ends with Commit or Rollback.
- A unique level of transaction is possible in the SAFE X3 engine. Nesting a Trbegin in a Subprog called by a script already running a transaction generates an error.
- adxlog can be tested to see if a transaction is already in progress.
Main consequences on the Sage X3 code
- Do not use transactions when creating code to handle the method of an entity. As methods are usually called interactively within a context, creating a transaction that updates the database is not consistent. The
AUPDATE
,AINSERT
, andADELETE
methods are running the transaction. However, the code related to the "begin" and "end" transactions is completely embedded by the supervisor, and does not need to be managed by the development partner. - An operation performs updates within a transaction. The development partner can use the parameters given during the operation call, manage the resources needed, perform a transaction, and return a result. For example, in a query that updates the database, an operation triggered from a link on a record executes a transaction.
- A subprogram declared by Subprog or Funprog can also manage a transaction if it executes updates triggered from another routine that performs the updates.
- To avoid issues with nested transactions when an operation or a subprog needs to handle transaction updates, make sure adxlog is equal to 0.
- If it is:
- If it is not:
- The transaction is embedded within another transaction (for example, if an operation on an entity calls operations on child entities).
- The development partner must perform the following:
- Skip the Trbegin step.
- Perform the database operation.
- Return a status, usually with a method such as ASETERROR.
- It is the responsibility of the calling operation to perform the Rollback if the operation fails.
- If it is:
Example
# Example of a transaction on a table (ACCOUNT) Subprog CREDIT_DEBIT(ACCOUNT1,ACCOUNT2,AMOUNT,RET_STATUS,RET_MESSAGE) Value Char ACCOUNT1, ACCOUNT2 Value Integer AMOUNT Variable Integer RET_STATUS Variable Char RET_MESSAGE() Local Integer TRANS_OPEN Local Char ACCOUNT_CODE Local File ACCOUNT [ACCOUNT] # Open a transaction if not opened If adxlog=0 TRANS_OPEN=0 Trbegin [ACCOUNT] Endif # Perform a credit / debit movement # CODE is a unique code so adxuprec can only return 0 or 1 Update [ACCOUNT] Where CODE=ACCOUNT1 With [ACCOUNT]BALANCE-AMOUNT If adxuprec=1 Update [ACCOUNT] Where CODE=ACCOUNT2 With [ACCOUNT]BALANCE+AMOUNT Else ACCOUNT_CODE=ACCOUNT1 Endif If adxuprec=0 ACCOUNT_CODE+=string(ACCOUNT_CODE="",ACCOUNT2) : # Contains the first account not found RET_STATUS=[V]CST_AERROR RET_MESSAGE="Account"-ACCOUNT_CODE-"not found" If TRANS_OPEN=0 Rollback Endif Else Raz RET_MESSAGE RET_STATUS=[V]CST_AOK If TRANS_OPEN=0 Commit Endif Endif End