## Release Notes: SeaORM 2.0.0-rc.36

*(since 2.0.0-rc.35)*

### 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:

```rust
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:

```rust
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
