On 4 mars 2013, at 01:07, Shai Berger <[email protected]> wrote:

>> On 1 mars 2013, at 13:48, Aymeric Augustin 
>> <[email protected]> wrote:
>> 
>> I'd like to add an @atomic decorator that:
>>      - Really guarantees atomicity, by raising an exception if you attempt 
>> commit within an atomic block,
> 
> Fragility alert: databases commit implicitly. Most notably, Oracle and MySql 
> for every DDL command.

That a good point. I hadn't considered DDL.

> It is true that the commands that trigger this are not usually found in 
> normally-executed application
> code. However, since the proposal is all about running in autocommit mode 
> unless a transaction
> was started explicitly, it should be noted that once such a command is 
> executed, it does not
> just break the transaction in the middle, it renders everything after it 
> non-transactional.

I checked each supported database to determine whether this behavior would be 
expected.

PostgreSQL supports transactional DDL. (The PostgreSQL wiki also indicates that 
most
databases that have a third-party adapter for Django support DDL, which is good 
news:
http://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis)

SQLite supports transactional DDL — its implementation of transactions with a 
file lock
guarantees that anything can be done in a transaction. The Python sqlite3 
module gets in the
way again: it will commit on DDL unless autocommit is on: 
http://bugs.python.org/issue10740.
This isn't as braindead as committing on SAVEPOINT, but quite regrettable 
nonetheless.
(I'm not weighting on these bugs because I believe that the default mode of 
sqlite3 is an
aberration that only exists to conform to PEP 249 and cannot be salvaged.)

On MySQL, Django will behave exactly like typing commands in the MySQL shell. 
This behavior
shouldn't come as a surprise. See 
http://dev.mysql.com/doc/refman/5.6/en/implicit-commit.html.

Oracle is the only database supported by Django that isn't designed for 
autocommit by default.
Its docs say: "Oracle Database implicitly commits the current transaction 
before and after every
DDL statement." This sentence is obviously written with implicit transaction 
initiation in mind.
This behavior will be surprising for someone used to Oracle's transaction 
model, but not much
more that autocommit in general. It's a logical consequence of "autocommit is 
on", "@atomic
opens a transaction", and "DDL commits the transaction".

Finally, a quick search on the web shows that it's considered bad form to rely 
on DDL to
implicitly commit transactions on databases that don't support transactional 
DDL.

> Most DDL commands executed by Django apps, 1.6 and on, should be done through 
> the upcoming
> schema alteration mechanisms -- code under core's control, so things can be 
> set up correctly 
> (that is, when such a command is executed under @atomic with a 
> non-DDL-transactional backend,
> it should raise an exception). They just need care.

Yes, it's a good idea to add this check when core gets support for DDL commands.

> Other than that, strong documentation warnings should be given around the use 
> of raw sql in transactions.

Agreed, this should be documented as a limitation of @atomic.

>>      - Supports nesting within an existing transaction, with savepoints.
> 
> The use of savepoints in Django apps so far has been very little, as far as I 
> know. One point
> I'm unsure of is the interaction of savepoints with cursors, since querysets 
> are lazy; so the scenario
> I'm worrirf about is, generally speaking,
> 
> @atomic
> def main():
>       for obj in query_with_more_than_100_objects:
>               try:
>                       handle(obj)
>               except Bad:
>                       pass
> 
> @atomic
> def handle(obj):
>       if good(obj):
>               mark_good(obj)
>               obj.save()
>       else:
>               raise Bad(obj)
> 
> Will the next (database) fetch after an exception is raised get the right 
> objects?
> 
> My reading of the Postgresql documentation is that it will do the right 
> thing, not so sure about
> the other backends.

Django currently doesn't support server side cursors — at least on PostgreSQL, 
most likely on
other databases too. Accessing the first object loads the entire queryset 
instantly.

I suspect it's the database's job to handle this properly (maybe by raising an 
exception). For
example, I know that SQLite is smart enough to deal properly with equivalent 
scenarios using
the C API: it delays committing the transaction until all reads are finished. I 
don't know how
other databases deal with this in general.

-- 
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.


Reply via email to