github SeaQL/sea-orm 2.0.0-rc.36

8 hours ago

New Features

Per-Migration Transaction Control (#2980)

Previously, all Postgres migrations ran inside a single batch transaction, while MySQL and SQLite ran without one. This was an all-or-nothing approach with no way to opt out for individual migrations (e.g. CREATE INDEX CONCURRENTLY on Postgres requires running outside a transaction).

MigrationTrait now has a use_transaction() method to control this per migration:

impl MigrationTrait for Migration {
    fn use_transaction(&self) -> Option<bool> {
        Some(false) // opt out of automatic transaction
    }
}
  • None (default): follow backend convention — Postgres uses a transaction, MySQL/SQLite do not
  • Some(true): force a transaction on any backend
  • Some(false): disable automatic transaction wrapping

For migrations that opt out, SchemaManager::begin() and SchemaManager::commit() allow manual transaction control within the migration body:

async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
    // DDL in a transaction
    let m = manager.begin().await?;
    m.create_table(
        Table::create()
            .table("my_table")
            .col(pk_auto("id"))
            .col(string("name"))
            .to_owned(),
    ).await?;
    m.commit().await?;

    // Non-transactional DDL
    manager.get_connection()
        .execute_unprepared("CREATE INDEX CONCURRENTLY idx_name ON my_table (name)")
        .await?;
    Ok(())
}

Core changes:

  • Added OwnedTransaction variant to DatabaseExecutor, enabling SchemaManager to own a transaction
  • Added DatabaseExecutor::is_transaction() for runtime introspection
  • Each migration is now wrapped individually rather than in a batch

Don't miss a new sea-orm release

NewReleases is sending notifications on new releases.