From d9c96c4836121ca7a91bffe57153b21d95e3dac4 Mon Sep 17 00:00:00 2001 From: Alexander Sandor <137198655+SandPod@users.noreply.github.com> Date: Fri, 13 Dec 2024 09:52:04 +0100 Subject: [PATCH] fix: Add documentation for transaction isolation level. (#222) * fix: improve transaction description correctness. * fix: add documentation for transaction isolation level. * fix(review): Remove redundant transaction information. * fix(review): Reduce redundant information in example. * fix: Improve naming of transaction constant value. * fix(reivew): Typo Co-authored-by: Hampus Lavin --------- Co-authored-by: Hampus Lavin --- .../06-database/08-transactions.md | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/06-concepts/06-database/08-transactions.md b/docs/06-concepts/06-database/08-transactions.md index 3b9b08ec..a99e05bb 100644 --- a/docs/06-concepts/06-database/08-transactions.md +++ b/docs/06-concepts/06-database/08-transactions.md @@ -2,7 +2,9 @@ The essential point of a database 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. -Serverpod handles database transactions through the `session.db.transaction` method. The transaction takes a method that performs any database queries or other operations and optionally returns a value. +Serverpod handles database transactions through the `session.db.transaction` method. The method takes a callback function that receives a transaction object. + +The transaction is committed when the callback function returns, and rolled back if an exception is thrown. Any return value of the callback function is returned by the `transaction` method. Simply pass the transaction object to each database operation method to include them in the same atomic operation: @@ -18,3 +20,38 @@ var result = await session.db.transaction((transaction) async { ``` In the example we insert a company and an employee in the same transaction. If any of the operations fail, the entire transaction will be rolled back and no changes will be made to the database. If the transaction is successful, the return value will be `true`. + +## Transaction isolation + +The transaction isolation level can be configured when initiating a transaction. The isolation level determines how the transaction interacts with concurrent database operations. If no isolation level is supplied, the level is determined by the database engine. + +:::info + +At the time of writing, the default isolation level for the PostgreSQL database engine is `IsolationLevel.readCommitted`. + +::: + +To set the isolation level, configure the `isolationLevel` property of the `TransactionSettings` object: + +```dart +await session.db.transaction( + (transaction) async { + await Company.db.insertRow(session, company, transaction: transaction); + await Employee.db.insertRow(session, employee, transaction: transaction); + }, + settings: TransactionSettings(isolationLevel: IsolationLevel.serializable), +); +``` + +In the example the isolation level is set to `IsolationLevel.serializable`. + +The available isolation levels are: + +| Isolation Level | Constant | Description | +|-----------------|-----------------------|-------------| +| Read uncommitted | `IsolationLevel.readUncommitted` | Exhibits the same behavior as `IsolationLevel.readCommitted` in PostgresSQL | +| Read committed | `IsolationLevel.readCommitted` | Each statement in the transaction sees a snapshot of the database as of the beginning of that statement. | +| Repeatable read | `IsolationLevel.repeatableRead` | The transaction only observes rows committed before the first statement in the transaction was executed giving a consistent view of the database. If any conflicting writes among concurrent transactions occur, an exception is thrown. | +| Serializable | `IsolationLevel.serializable` | Gives the same guarantees as `IsolationLevel.repeatableRead` but also throws if read rows are updated by other transactions. | + +For a detailed explanation of the different isolation levels, see the [PostgreSQL documentation](https://www.postgresql.org/docs/current/transaction-iso.html).