Transactions in YSQL
In YugabyteDB, a transaction is a sequence of operations performed as a single logical unit of work. The essential point of a transaction is that it bundles multiple steps into a single, all-or-nothing operation. The intermediate states between the steps are not visible to other concurrent transactions, and if some failure occurs that prevents the transaction from completing, then none of the steps affect the database at all.
Overview
In YugabyteDB, a transaction is the set of commands inside a BEGIN - COMMIT block. For example:
BEGIN;
UPDATE accounts SET balance = balance + 1000.00 WHERE name = 'John Smith';
-- other statements
COMMIT;
The BEGIN
and COMMIT
block is needed when you have multiple statements to be executed as part of a transaction. YugabyteDB treats every ad-hoc individual SQL statement as being executed in a transaction.
If you decide to cancel the transaction and not commit it, you can issue a ROLLBACK
instead of a COMMIT
. You can also control the rollback of a subset of statements using SAVEPOINT
. After rolling back to a savepoint, it continues to be defined, so you can roll back to it several times.
As all transactions in YugabyteDB are guaranteed to be ACID compliant, errors can be thrown during transaction processing to ensure correctness guarantees are not violated. YugabyteDB returns different error codes for each case with details. Applications need to be designed to do retries correctly for high availability.
Typical commands
The following commands are typically involved in a transaction flow:
Command | Description | Example |
---|---|---|
BEGIN | Start a transaction. This is the first statement in a transaction. | BEGIN TRANSACTION |
SET | Set session-level transaction settings | SET idle_in_transaction_session_timeout = 10000 |
SHOW | Display session-level transaction settings | SHOW idle_in_transaction_session_timeout |
SET TRANSACTION | Set the isolation level. | SET TRANSACTION SERIALIZABLE |
SAVEPOINT | Create a checkpoint. | SAVEPOINT yb_save |
ROLLBACK TO SAVEPOINT | Rollback to a specific savepoint. | ROLLBACK TO SAVEPOINT yb_save |
RELEASE SAVEPOINT | Destroy a savepoint. | RELEASE yb_save |
ROLLBACK | Cancel a transaction. | ROLLBACK |
COMMIT | Apply the transaction to the tables. | COMMIT |
Concurrency control
Isolation levels
The isolation level defines the level of data visibility to the transaction. YugabyteDB supports multi-version concurrency control (MVCC), which enables the isolation of concurrent transactions without the need for locking.
YugabyteDB supports three kinds of isolation levels to support different application needs.
Level | Description |
---|---|
Repeatable Read (Snapshot) | Only the data that is committed before the transaction began is visible to the transaction. Effectively, the transaction sees the snapshot of the database as of the start of the transaction.
Applications using this isolation level should be designed to retry on serialization failures.
|
Read CommittedEA | Each statement of the transaction sees the latest data committed by any concurrent transaction just before the execution of the statement. If another transaction has modified a row related to the current transaction, the current transaction waits for the other transaction to commit or rollback its changes.
The server internally waits and retries on conflicts, so applications need not retry on serialization failures.
|
Serializable | This is the strictest isolation level and has the effect of all transactions being executed in a serial manner, one after the other rather than in parallel.
Applications using this isolation level should be designed to retry on serialization failures.
|
Explicit locking
Typically SELECT statements do not automatically lock the rows fetched during a transaction. Depending on your application needs, you might have to lock the rows retrieved during SELECT. YugabyteDB supports explicit row-level locking for such cases and ensures that no two transactions can hold locks on the same row. Lock acquisition conflicts are resolved according to concurrency control policies.
Lock acquisition has the following format:
SELECT * FROM txndemo WHERE k=1 FOR UPDATE;
YugabyteDB supports the following types of explicit row locks:
Lock | Description |
---|---|
FOR UPDATE | Strongest and exclusive lock. Prevents all other locks on these rows till the transaction ends. |
FOR NO KEY UPDATE | Weaker than FOR UPDATE and exclusive. Will not block FOR KEY SHARE commands. |
FOR SHARE | Shared lock that does not block other FOR SHARE and FOR KEY SHARE commands. |
FOR KEY SHARE | Shared lock that does not block other FOR SHARE , FOR KEY SHARE , and FOR NO KEY UPDATE commands. |
Retry on failures
During transaction processing, failures can happen due to the strong ACID properties guaranteed by YugabyteDB. Appropriate error codes are returned for each scenario and applications should adopt the right retry mechanisms specific to the isolation levels it uses to be highly available. In general, the error codes can be classified into the following three types:
-
WARNING. Informational messages that explain why a statement failed. For example:
-- When a BEGIN statement is issued inside a transaction WARNING: 25001: there is already a transaction in progress
Most client libraries hide warnings, but you might notice the messages when you execute statements directly from a terminal. The statement execution can continue without interruption but would need to be modified to avoid the re-occurrence of the message.
-
ERROR: Errors are returned when a transaction cannot continue and has to be restarted by the client. For example:
-- When multiple transactions are modifying the same key. ERROR: 40001: Operation expired: Transaction XXXX expired or aborted by a conflict
These errors need to be handled by the application to take appropriate action.
-
FATAL. Fatal messages are returned to notify that the connection to a server has been disconnected. For example:
-- When the application takes a long time to issue a statement in the middle of a transaction. FATAL: 25P03: terminating connection due to idle-in-transaction timeout
At this point, the application should reconnect to the server.
For more details on how to handle failures and retry, see Transaction retries.
For an example application and try it out yourself, see Designing a Retry Mechanism for Resilient Spring Boot Applications.
Tuning for high performance
All applications need to be tuned to get the best performance. YugabyteDB supports various constructs and multiple settings that can be adopted and tuned to your needs. Adopting the correct constructs in the right scenarios can immensely improve the performance of your application. Some examples are:
- Convert a multi-statement transaction affecting a single row into a fast-path transaction.
- Avoid long waits with the right timeouts.
- Minimize conflict errors with
ON CONFLICT
clause. - Uninterrupted long scans
- Minimize round trips with stored procedures.
Observability
YugabyteDB exports a lot of observable metrics so that you can see what is going on in your cluster. These metrics can be exported to Prometheus and visualized in Grafana. Many of these metrics are also displayed as charts in YugabyteDB Anywhere and YugabyteDB Aeon. The following are key transaction-related metrics.
transactions_running
Shows the number of transactions that are currently active. This provides an overview of how transaction intensive the cluster currently is.
transaction_conflicts
Describes the number of times transactions have conflicted with other transactions. An increase in the number of conflicts could directly result in increased latency of your applications.
expired_transactions
Shows the number of transactions that did not complete because the status tablet did not receive enough heartbeats from the node to which the client had connected. This usually happens if that node or process managing the transaction has crashed.
Session-level settings
The following YSQL parameters affect transactions and can be configured to your application needs. These settings can be set using the SET command and the current values can be fetched using the SHOW command.
Note
These settings impact all transactions in the current session only.default_transaction_read_only
Turn this setting ON/TRUE/1
to make all the transactions in the current session read-only. This is helpful when you want to run reports or set up follower reads.
SET default_transaction_read_only = TRUE;
default_transaction_isolation
Set this to one of serializable
, repeatable read
, or read committed
. This sets the default isolation level for all transactions in the current session.
SET default_transaction_isolation = 'serializable';
default_transaction_deferrable
Turn this setting ON/TRUE/1
to make all the transactions in the current session deferrable. This ensures that the transactions are not canceled by a serialization failure.
SET default_transaction_deferrable = TRUE;
Note
TheDEFERRABLE
transaction property has no effect unless the transaction is also SERIALIZABLE
and READ ONLY
.
idle_in_transaction_session_timeout
Set this to a duration (for example, '10s or 1000'
) to limit delays in transaction statements. The default time unit is milliseconds. See Handle idle transactions.
yb_transaction_priority_lower_bound
Set this to values in the range [0.0 - 1.0]
to set the lower bound of the dynamic priority assignment. See Optimistic concurrency control.
yb_transaction_priority_upper_bound
Set this to values in the range [0.0 - 1.0]
to set the upper bound of the dynamic priority assignment. See Optimistic concurrency control.
Learn more
- Transaction error codes - Various error codes returned during transaction processing.
- Transaction error handling - Methods to handle various error codes to design highly available applications.
- Transaction isolation levels - Various isolation levels supported by YugabyteDB.
- Concurrency control - Policies to handle conflicts between transactions.
- Transaction priorities - Priority buckets for transactions.
- Transaction options - Options supported by transactions.