| 236 | === Other news === |
| 237 | ==== `trac.db.util.with_transaction()` ^[source:trunk/trac/db/util.py@9701:23-78#L22 (0.12)]^ ==== #with_transaction |
| 238 | |
| 239 | The `@with_transaction(env)` decorator replaces the current practice of getting a database connection with `env.get_db_cnx()` and issuing an explicit commit or rollback. Applied to a local function, it calls that function with a database connection as an argument, and either issues a commit if the function terminates normally, or a rollback if the function raises an exception. In the latter case, the exception is re-raised. |
| 240 | |
| 241 | This makes transactions much more robust, as we can guarantee that any mutating operations on the database are either committed or rolled back. This should avoid issues like #8443, where transactions were kept open in IDLE state. |
| 242 | |
| 243 | This mechanism also handles transaction nesting automatically, by only committing or rolling back in the outermost transaction block. This avoids having to pass a `db` argument around, like was typically done in model object methods like [source:trunk/trac/wiki/model.py@9701:120#L119 WikiPage.save()]. The `db` argument is still supported for backward compatibility in methods that were present in 0.11, but is deprecated and should not be used in new code. |
| 244 | |
| 245 | To avoid having to import `with_transaction` from `trac.db.util` in every module using transactions, it can also be called conveniently on the environment as `@env.with_transaction()`. |
| 246 | |
| 247 | Implementing this mechanism as a function decorator is an intermediate solution until the `with` statement and context managers become available (once we drop support for Python 2.4). |
| 248 | |
| 249 | See #8751 for details. |