#22496 closed Bug (fixed)
Data migrations are not transactional (except on Postgres)
Reported by: | Shai Berger | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | dev |
Severity: | Release blocker | Keywords: | oracle mysql sqlite |
Cc: | Aymeric Augustin, Andrew Godwin | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | yes |
Needs tests: | yes | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
In e74d2183c28467aefc0b87e3fa6d405dbfdea82c (master) and 9bf890f6f9d137d5b86fd9a6a38fb11c5d21b1af (1.7.x) schema editor was made not to open transactions for backends that cannot roll back DDL. However, there is nothing else that starts transactions in migrations, even if they are data migrations -- so now, of the backends in core, migrations are only transactional on PostgreSQL.
This is a spin-off from #22483.
Change History (6)
comment:1 by , 11 years ago
comment:4 by , 11 years ago
My vote is that we definitely leave RunSQL as non-transactional on MySQL and Oracle (SeparateDatabaseAndState is a combiner, it should be left alone too).
I also agree that we should have RunPython in a transaction, but have an argument to turn it off if you're doing schema changes on Oracle (the only know crash case I know of). I'll commit that now and mark this as fixed.
comment:5 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
First, we should set
can_rollback_ddl = True
for SQLite. SQLite fully supports transactional DDL, even thouh the Python sqlite3 module goes to great lengths to prevent developers from using that capability. With the new transaction model introduced in Django 1.6, I believe this change is safe.This leaves MySQL and Oracle. Let's consider special operations:
cursor.execute
, among other things.In fact the real question is the failure mode when running DDL in a transaction. If the transaction simply gets committed, it isn't great (because of the mismatch between the actual transaction state and what Django believes the state is) but it's acceptable. If Django crashes, it's bad :-) We may get bitten by "Oracle needs to close and reopen the connection after DDL" again...
If we decide to make these operations transactional, perhaps that could be controlled by an
atomic
flag or keyword argument to theOperation
class. (Looking at the code, it would require a refactoring.) A simpler solution would be to decoratedatabase_forwards/backwards
with@atomic
but that would make subclassing more difficult to get right.The alternative is to leave transaction management entirely up to the user. But users aren't good at transaction management in general.
If I had to choose, I would go for an
atomic
flag that's enabled by default for the three special operations but can be turned off by users who're running into one of the edge cases where the transaction prevents the operation from executing.