On 1 mars 2013, at 13:48, Aymeric Augustin <[email protected]> wrote:
> Basically, Django intends to provide autocommit by default. Rather than fight > the database adapter that itselfs fights the database, I propose to simply > turn autocommit on, and stop implicitly starting and committing transactions. > Explicit is better than implicit. This is implemented in https://github.com/django/django/pull/873 and ready for review. Important notes: - Some ORM APIs aren't atomic any longer, as noted by Shai and Christophe; others are using a hack: `enter_transaction_management(forced=True)`. I need a better transaction API to fix that, see below. - I disabled three tests that tested the internals of transaction management in non-autocommit mode, which no longer exists. I don't know how much I'm going to refactor, so I haven't rewritten them yet. I'd like to merge to master at this point, since I've reached a consistent, if not final, state. > This obviously has far-reaching consequences on transaction handling in > Django, but the current APIs should still work. (Fixing them is part 2 of the > plan.) Part 2 of the plan is more ambitious — it's about improving the transaction APIs. Here's the general idea. Currently, the most useful but also most problematic API is the @commit_on_success decorator. It's confusing because it mixes two roles. 1) Switch the transaction state from "auto mode" to "managed mode" ie. disable autocommit. - Nesting works as expected because transaction state is managed as a stack. - This stack is a pillar of the current implementation but I'm not convinced that it's an useful concept in general. 2) Define the context for a transaction — but in a very fragile way. - It doesn't guarantee to rollback all changes if an exception occurs, because you can commit within the block. - Nesting breaks atomicity, because the inner block triggers a commit or rollback before the end of the outer block. - To sum up, it really does what the name says, and nothing else :) I'd like to add an @atomic decorator that: - Really guarantees atomicity, by raising an exception if you attempt commit within an atomic block, - Supports nesting within an existing transaction, with savepoints. - In option, support "merging" with an existing transaction, for pathological cases where the overhead of savepoints would be excessive: @atomic(merge=True) Partial rollback is very Pythonic: it works by raising an exception and catching it higher in the stack. Each @atomic context that's exited with an exception rolls back to its savepoint. Ideally, this decorator would start a transaction but not enable "managed mode". The point of "managed mode" is that you can commit at any time, and the next query will automatically reopen a transaction. Since @atomic forbids committing until the end of the block, this is no longer a useful property. Another good reason for staying in "auto mode" is that savepoints don't work on SQLite in "managed mode": cursor.execute("SAVEPOINT foo") triggers a COMMIT because Python's sqlite3 module tries to be smart and fails miserably. The end goal is: - for defining transaction blocks: to deprecate @commit_on_success / @commit_manually and provide @atomic instead. - for controlling transaction state: to deprecate @commit_on_success / @autocommit and provide connection.set_autocommit(False/True) instead — only usable outside @atomic - for the TransactionMiddleware: to provide exactly the same semantics as @atomic, and to keep the ability to disable it with @autocommit - to remove the stack of transaction states, which mostly exists to support the current decorators, once the deprecation cycle completes. Of course the two APIs should work in parallel until the old ones are gone. I'm reasonably confident that this plan can work. -- Aymeric. -- You received this message because you are subscribed to the Google Groups "Django developers" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/django-developers?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
