Transaction Management
Relevant source files
The following files were used as context for generating this wiki page:
Transaction Management in SeaORM 2.0 provides a robust mechanism for ensuring atomicity and data integrity across database operations. It supports both asynchronous and synchronous execution models, allowing developers to group multiple operations—such as inserts, updates, and deletes—into a single logical unit of work that either succeeds completely or rolls back on failure.
The system is designed to handle complex relational persistence, including nested object graphs and self-referential models. It leverages the TransactionTrait to provide a unified API across different database backends like MySQL, PostgreSQL, and SQLite, supporting various isolation levels and access modes to fine-tune concurrency behavior.
Sources: src/lib.rs:182-198, sea-orm-sync/src/lib.rs:182-198
Transaction Execution Models
SeaORM supports two primary execution environments for transactions: Async (standard) and Sync (via sea-orm-sync).
Async Transactions
In the standard async environment, transactions are typically executed using the transaction method on a database connection. This method accepts a closure that returns a Future. If the closure returns Ok, the transaction is committed; if it returns Err, it is automatically rolled back.
Sources: src/lib.rs:192-198, src/docs.rs:1-80
Synchronous Transactions
The sea-orm-sync crate provides a synchronous version of the API, removing the requirement for an async runtime. This is particularly useful for lightweight CLI applications or environments where rusqlite is used. The logic remains identical to the async version but without .await calls.
Sources: sea-orm-sync/src/lib.rs:253-255, sea-orm-sync/CLAUDE.md:1-15
Core Transaction APIs
SeaORM provides multiple ways to initiate and manage transactions depending on the required level of control.
Closure-based Transactions
The most common approach is using the transaction closure. This handles the lifecycle (Begin, Commit/Rollback) automatically based on the result of the closure.
The diagram shows the automated lifecycle of a closure-based transaction in SeaORM.
Sources: sea-orm-sync/tests/transaction_tests.rs:43-58, sea-orm-sync/tests/transaction_tests.rs:252-277
Manual Transaction Control
For scenarios where a closure is not suitable, developers can manually control the transaction lifecycle using begin(), commit(), and rollback(). If a DatabaseTransaction object is dropped without calling commit(), it triggers an automatic rollback.
Sources: sea-orm-sync/tests/transaction_tests.rs:118-140, sea-orm-sync/tests/transaction_tests.rs:175-197
Configuration Options
Transactions can be customized using TransactionOptions or the transaction_with_config method.
| Configuration | Supported Values | Description |
|---|---|---|
| Isolation Level | RepeatableRead, ReadCommitted, ReadUncommitted, Serializable | Defines how the transaction is isolated from others. |
| Access Mode | ReadOnly, ReadWrite | Specifies if the transaction can modify data. |
| Sqlite Mode | Immediate, Deferred, Exclusive | Specific to SQLite backends. |
Sources: sea-orm-sync/tests/transaction_tests.rs:569-605, sea-orm-sync/tests/transaction_tests.rs:629-654
Nested Transactions and Savepoints
SeaORM supports nested transactions. When a transaction is initiated inside an existing one, SeaORM typically uses database Savepoints to manage the sub-transaction.
This sequence illustrates how SeaORM uses savepoints to allow independent rollback of nested units of work.
Sources: sea-orm-sync/tests/transaction_tests.rs:369-509, sea-orm-sync/tests/transaction_tests.rs:512-626
Transactions in Migrations
SeaORM's migration system uses transactions to ensure schema changes are atomic. By default, PostgreSQL wraps each migration in a transaction, whereas other backends like MySQL may auto-commit DDL statements.
Migration Transaction Behavior
- Default: Backend-specific behavior (e.g., Postgres wraps by default).
- Forced: Using
use_transaction = Some(true)forces transactions where supported. - Disabled: Using
use_transaction = Some(false)allows DDL execution outside a transaction, which is sometimes required for specific operations like concurrent index creation in Postgres.
Sources: sea-orm-migration/tests/main.rs:232-264, sea-orm-migration/tests/main.rs:296-330
Advanced Persistence within Transactions
ActiveModel's builder pattern allows for complex nested persistence within a transaction. SeaORM automatically calculates the dependency graph and executes operations in the correct topological order.
// Operations performed within a single atomic unit
let user = user::ActiveModel::builder()
.set_name("Bob")
.set_profile(profile::ActiveModel::builder().set_picture("image.jpg")) // 1-1
.add_post(
post::ActiveModel::builder()
.set_title("Nice weather")
.add_tag(tag::ActiveModel::builder().set_tag("sunny")), // M-N
)
.save(db)
.await?;
Sources: src/lib.rs:152-168, CLAUDE.md:65-90
RBAC and Restricted Transactions
When the rbac feature is enabled, transactions can be initiated on restricted database connections. The Role-Based Access Control (RBAC) engine ensures that even within a transaction, the user only performs operations they are authorized for.
Sources: sea-orm-sync/tests/transaction_tests.rs:63-88, sea-orm-sync/tests/transaction_tests.rs:143-172
Transaction management in SeaORM 2.0 ensures that complex, multi-step operations remain consistent and reliable, providing developers with both high-level automated closures and low-level manual controls to suit various architectural needs.