|
@@ -206,18 +206,6 @@ class Atomic(object):
|
|
|
self.using = using
|
|
|
self.savepoint = savepoint
|
|
|
|
|
|
- def _legacy_enter_transaction_management(self, connection):
|
|
|
- if not connection.in_atomic_block:
|
|
|
- if connection.transaction_state and connection.transaction_state[-1]:
|
|
|
- connection._atomic_forced_unmanaged = True
|
|
|
- connection.enter_transaction_management(managed=False)
|
|
|
- else:
|
|
|
- connection._atomic_forced_unmanaged = False
|
|
|
-
|
|
|
- def _legacy_leave_transaction_management(self, connection):
|
|
|
- if not connection.in_atomic_block and connection._atomic_forced_unmanaged:
|
|
|
- connection.leave_transaction_management()
|
|
|
-
|
|
|
def __enter__(self):
|
|
|
connection = get_connection(self.using)
|
|
|
|
|
@@ -225,12 +213,31 @@ class Atomic(object):
|
|
|
|
|
|
connection.ensure_connection()
|
|
|
|
|
|
-
|
|
|
- self._legacy_enter_transaction_management(connection)
|
|
|
-
|
|
|
- if not connection.in_atomic_block and not connection.autocommit:
|
|
|
- raise TransactionManagementError(
|
|
|
- "'atomic' cannot be used when autocommit is disabled.")
|
|
|
+ if not connection.in_atomic_block:
|
|
|
+
|
|
|
+ connection.commit_on_exit = True
|
|
|
+ connection.needs_rollback = False
|
|
|
+ if not connection.autocommit:
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if connection.features.autocommits_when_autocommit_is_off:
|
|
|
+ raise TransactionManagementError(
|
|
|
+ "Your database backend doesn't behave properly when "
|
|
|
+ "autocommit is off. Turn it on before using 'atomic'.")
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if not self.savepoint:
|
|
|
+ raise TransactionManagementError(
|
|
|
+ "The outermost 'atomic' block cannot use "
|
|
|
+ "savepoint = False when autocommit is off.")
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ connection.in_atomic_block = True
|
|
|
+ connection.commit_on_exit = False
|
|
|
|
|
|
if connection.in_atomic_block:
|
|
|
|
|
@@ -255,63 +262,58 @@ class Atomic(object):
|
|
|
else:
|
|
|
connection.set_autocommit(False)
|
|
|
connection.in_atomic_block = True
|
|
|
- connection.needs_rollback = False
|
|
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
|
connection = get_connection(self.using)
|
|
|
- if exc_value is None and not connection.needs_rollback:
|
|
|
- if connection.savepoint_ids:
|
|
|
-
|
|
|
- sid = connection.savepoint_ids.pop()
|
|
|
- if sid is not None:
|
|
|
+
|
|
|
+ if connection.savepoint_ids:
|
|
|
+ sid = connection.savepoint_ids.pop()
|
|
|
+ else:
|
|
|
+
|
|
|
+ connection.in_atomic_block = False
|
|
|
+
|
|
|
+ try:
|
|
|
+ if exc_value is None and not connection.needs_rollback:
|
|
|
+ if connection.in_atomic_block:
|
|
|
+
|
|
|
+ if sid is not None:
|
|
|
+ try:
|
|
|
+ connection.savepoint_commit(sid)
|
|
|
+ except DatabaseError:
|
|
|
+ connection.savepoint_rollback(sid)
|
|
|
+ raise
|
|
|
+ else:
|
|
|
+
|
|
|
try:
|
|
|
- connection.savepoint_commit(sid)
|
|
|
+ connection.commit()
|
|
|
except DatabaseError:
|
|
|
- connection.savepoint_rollback(sid)
|
|
|
-
|
|
|
- self._legacy_leave_transaction_management(connection)
|
|
|
+ connection.rollback()
|
|
|
raise
|
|
|
else:
|
|
|
-
|
|
|
- connection.in_atomic_block = False
|
|
|
- try:
|
|
|
- connection.commit()
|
|
|
- except DatabaseError:
|
|
|
- connection.rollback()
|
|
|
-
|
|
|
- self._legacy_leave_transaction_management(connection)
|
|
|
- raise
|
|
|
- finally:
|
|
|
- if connection.features.autocommits_when_autocommit_is_off:
|
|
|
- connection.autocommit = True
|
|
|
+
|
|
|
+
|
|
|
+ connection.needs_rollback = False
|
|
|
+ if connection.in_atomic_block:
|
|
|
+
|
|
|
+
|
|
|
+ if sid is None:
|
|
|
+ connection.needs_rollback = True
|
|
|
else:
|
|
|
- connection.set_autocommit(True)
|
|
|
- else:
|
|
|
-
|
|
|
-
|
|
|
- connection.needs_rollback = False
|
|
|
- if connection.savepoint_ids:
|
|
|
-
|
|
|
-
|
|
|
- sid = connection.savepoint_ids.pop()
|
|
|
- if sid is None:
|
|
|
- connection.needs_rollback = True
|
|
|
+ connection.savepoint_rollback(sid)
|
|
|
else:
|
|
|
- connection.savepoint_rollback(sid)
|
|
|
- else:
|
|
|
-
|
|
|
- connection.in_atomic_block = False
|
|
|
- try:
|
|
|
+
|
|
|
connection.rollback()
|
|
|
- finally:
|
|
|
- if connection.features.autocommits_when_autocommit_is_off:
|
|
|
- connection.autocommit = True
|
|
|
- else:
|
|
|
- connection.set_autocommit(True)
|
|
|
-
|
|
|
-
|
|
|
- self._legacy_leave_transaction_management(connection)
|
|
|
|
|
|
+ finally:
|
|
|
+
|
|
|
+ if not connection.in_atomic_block:
|
|
|
+ if connection.features.autocommits_when_autocommit_is_off:
|
|
|
+ connection.autocommit = True
|
|
|
+ else:
|
|
|
+ connection.set_autocommit(True)
|
|
|
+
|
|
|
+ elif not connection.savepoint_ids and not connection.commit_on_exit:
|
|
|
+ connection.in_atomic_block = False
|
|
|
|
|
|
def __call__(self, func):
|
|
|
@wraps(func, assigned=available_attrs(func))
|
|
@@ -331,24 +333,6 @@ def atomic(using=None, savepoint=True):
|
|
|
return Atomic(using, savepoint)
|
|
|
|
|
|
|
|
|
-def atomic_if_autocommit(using=None, savepoint=True):
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- db = DEFAULT_DB_ALIAS if callable(using) else using
|
|
|
- autocommit = get_connection(db).settings_dict['AUTOCOMMIT']
|
|
|
-
|
|
|
- if autocommit:
|
|
|
- return atomic(using, savepoint)
|
|
|
- else:
|
|
|
-
|
|
|
- if callable(using):
|
|
|
- return using
|
|
|
-
|
|
|
- else:
|
|
|
- return lambda func: func
|
|
|
-
|
|
|
-
|
|
|
|
|
|
|
|
|
|
|
@@ -472,16 +456,15 @@ def commit_on_success_unless_managed(using=None, savepoint=False):
|
|
|
Transitory API to preserve backwards-compatibility while refactoring.
|
|
|
|
|
|
Once the legacy transaction management is fully deprecated, this should
|
|
|
- simply be replaced by atomic_if_autocommit. Until then, it's necessary to
|
|
|
- avoid making a commit where Django didn't use to, since entering atomic in
|
|
|
- managed mode triggers a commmit.
|
|
|
+ simply be replaced by atomic. Until then, it's necessary to guarantee that
|
|
|
+ a commit occurs on exit, which atomic doesn't do when it's nested.
|
|
|
|
|
|
Unlike atomic, savepoint defaults to False because that's closer to the
|
|
|
legacy behavior.
|
|
|
"""
|
|
|
connection = get_connection(using)
|
|
|
if connection.autocommit or connection.in_atomic_block:
|
|
|
- return atomic_if_autocommit(using, savepoint)
|
|
|
+ return atomic(using, savepoint)
|
|
|
else:
|
|
|
def entering(using):
|
|
|
pass
|