changelog/2.0.0-rc.36.md
(since 2.0.0-rc.35)
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 notSome(true): force a transaction on any backendSome(false): disable automatic transaction wrappingFor 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:
OwnedTransaction variant to DatabaseExecutor, enabling SchemaManager to own a transactionDatabaseExecutor::is_transaction() for runtime introspection