Permalink
Browse files

Removed legacy transaction management per the deprecation timeline.

  • Loading branch information...
1 parent 907ac64 commit 0f9560855e5ed203b8c911c23237826e28a62a38 @aaugustin aaugustin committed Mar 21, 2014
@@ -500,7 +500,7 @@ def _clear(self, queryset, bulk):
if bulk:
queryset.delete()
else:
- with transaction.commit_on_success_unless_managed(using=db, savepoint=False):
+ with transaction.atomic(using=db, savepoint=False):
for obj in queryset:
obj.delete()
_clear.alters_data = True
@@ -71,7 +71,7 @@ def create_table(self, database, tablename):
for i, line in enumerate(table_output):
full_statement.append(' %s%s' % (line, ',' if i < len(table_output) - 1 else ''))
full_statement.append(');')
- with transaction.commit_on_success_unless_managed():
+ with transaction.atomic():
with connection.cursor() as curs:
try:
curs.execute("\n".join(full_statement))
@@ -63,7 +63,7 @@ def handle_noargs(self, **options):
if confirm == 'yes':
try:
- with transaction.commit_on_success_unless_managed():
+ with transaction.atomic():
with connection.cursor() as cursor:
for sql in sql_list:
cursor.execute(sql)
@@ -56,7 +56,7 @@ def handle(self, *fixture_labels, **options):
self.verbosity = int(options.get('verbosity'))
- with transaction.commit_on_success_unless_managed(using=self.using):
+ with transaction.atomic(using=self.using):
self.loaddata(fixture_labels)
# Close the DB connection -- unless we're still in a transaction. This
@@ -223,10 +223,6 @@ def model_installed(model):
for statement in sql:
cursor.execute(statement)
tables.append(connection.introspection.table_name_converter(model._meta.db_table))
-
- # We force a commit here, as that was the previous behavior.
- # If you can prove we don't need this, remove it.
- transaction.set_dirty(using=connection.alias)
finally:
cursor.close()
@@ -245,7 +241,7 @@ def model_installed(model):
if self.verbosity >= 2:
self.stdout.write(" Installing custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
try:
- with transaction.commit_on_success_unless_managed(using=connection.alias):
+ with transaction.atomic(using=connection.alias):
for sql in custom_sql:
cursor.execute(sql)
except Exception as e:
@@ -268,7 +264,7 @@ def model_installed(model):
if self.verbosity >= 2:
self.stdout.write(" Installing index for %s.%s model\n" % (app_name, model._meta.object_name))
try:
- with transaction.commit_on_success_unless_managed(using=connection.alias):
+ with transaction.atomic(using=connection.alias):
for sql in index_sql:
cursor.execute(sql)
except Exception as e:
View
@@ -77,20 +77,6 @@ def __delattr__(self, name):
backend = DefaultBackendProxy()
-def close_connection(**kwargs):
- warnings.warn(
- "close_connection is superseded by close_old_connections.",
- RemovedInDjango18Warning, stacklevel=2)
- # Avoid circular imports
- from django.db import transaction
- for conn in connections:
- # If an error happens here the connection will be left in broken
- # state. Once a good db connection is again available, the
- # connection state will be cleaned up.
- transaction.abort(conn)
- connections[conn].close()
-
-
# Register an event to reset saved queries when a Django request is started.
def reset_queries(**kwargs):
for conn in connections.all():
@@ -99,14 +85,9 @@ def reset_queries(**kwargs):
# Register an event to reset transaction state and close connections past
-# their lifetime. NB: abort() doesn't do anything outside of a transaction.
+# their lifetime.
def close_old_connections(**kwargs):
for conn in connections.all():
- # Remove this when the legacy transaction management goes away.
- try:
- conn.abort()
- except DatabaseError:
- pass
conn.close_if_unusable_or_obsolete()
signals.request_started.connect(close_old_connections)
signals.request_finished.connect(close_old_connections)
@@ -30,28 +30,25 @@ class BaseDatabaseWrapper(object):
def __init__(self, settings_dict, alias=DEFAULT_DB_ALIAS,
allow_thread_sharing=False):
+ # Connection related attributes.
+ self.connection = None
+ self.queries = []
# `settings_dict` should be a dictionary containing keys such as
# NAME, USER, etc. It's called `settings_dict` instead of `settings`
# to disambiguate it from Django settings modules.
- self.connection = None
- self.queries = []
self.settings_dict = settings_dict
self.alias = alias
self.use_debug_cursor = None
- # Savepoint management related attributes
- self.savepoint_state = 0
-
- # Transaction management related attributes
+ # Transaction related attributes.
+ # Tracks if the connection is in autocommit mode. Per PEP 249, by
+ # default, it isn't.
self.autocommit = False
- self.transaction_state = []
- # Tracks if the connection is believed to be in transaction. This is
- # set somewhat aggressively, as the DBAPI doesn't make it easy to
- # deduce if the connection is in transaction or not.
- self._dirty = False
# Tracks if the connection is in a transaction managed by 'atomic'.
self.in_atomic_block = False
- # List of savepoints created by 'atomic'
+ # Increment to generate unique savepoint ids.
+ self.savepoint_state = 0
+ # List of savepoints created by 'atomic'.
self.savepoint_ids = []
# Tracks if the outermost 'atomic' block should commit on exit,
# ie. if autocommit was active on entry.
@@ -60,11 +57,11 @@ def __init__(self, settings_dict, alias=DEFAULT_DB_ALIAS,
# available savepoint because of an exception in an inner block.
self.needs_rollback = False
- # Connection termination related attributes
+ # Connection termination related attributes.
self.close_at = None
self.errors_occurred = False
- # Thread-safety related attributes
+ # Thread-safety related attributes.
self.allow_thread_sharing = allow_thread_sharing
self._thread_ident = thread.get_ident()
@@ -166,7 +163,6 @@ def commit(self):
self.validate_thread_sharing()
self.validate_no_atomic_block()
self._commit()
- self.set_clean()
def rollback(self):
"""
@@ -175,7 +171,6 @@ def rollback(self):
self.validate_thread_sharing()
self.validate_no_atomic_block()
self._rollback()
- self.set_clean()
def close(self):
"""
@@ -189,7 +184,6 @@ def close(self):
self._close()
finally:
self.connection = None
- self.set_clean()
##### Backend-specific savepoint management methods #####
@@ -267,59 +261,6 @@ def _set_autocommit(self, autocommit):
##### Generic transaction management methods #####
- def enter_transaction_management(self, managed=True, forced=False):
- """
- Enters transaction management for a running thread. It must be balanced with
- the appropriate leave_transaction_management call, since the actual state is
- managed as a stack.
-
- The state and dirty flag are carried over from the surrounding block or
- from the settings, if there is no surrounding block (dirty is always false
- when no current block is running).
-
- If you switch off transaction management and there is a pending
- commit/rollback, the data will be committed, unless "forced" is True.
- """
- self.validate_no_atomic_block()
-
- self.transaction_state.append(managed)
-
- if not managed and self.is_dirty() and not forced:
- self.commit()
- self.set_clean()
-
- if managed == self.get_autocommit():
- self.set_autocommit(not managed)
-
- def leave_transaction_management(self):
- """
- Leaves transaction management for a running thread. A dirty flag is carried
- over to the surrounding block, as a commit will commit all changes, even
- those from outside. (Commits are on connection level.)
- """
- self.validate_no_atomic_block()
-
- if self.transaction_state:
- del self.transaction_state[-1]
- else:
- raise TransactionManagementError(
- "This code isn't under transaction management")
-
- if self.transaction_state:
- managed = self.transaction_state[-1]
- else:
- managed = not self.settings_dict['AUTOCOMMIT']
-
- if self._dirty:
- self.rollback()
- if managed == self.get_autocommit():
- self.set_autocommit(not managed)
- raise TransactionManagementError(
- "Transaction managed block ended with pending COMMIT/ROLLBACK")
-
- if managed == self.get_autocommit():
- self.set_autocommit(not managed)
-
def get_autocommit(self):
"""
Check the autocommit state.
@@ -368,41 +309,6 @@ def validate_no_broken_transaction(self):
"An error occurred in the current transaction. You can't "
"execute queries until the end of the 'atomic' block.")
- def abort(self):
- """
- Roll back any ongoing transaction and clean the transaction state
- stack.
- """
- if self._dirty:
- self.rollback()
- while self.transaction_state:
- self.leave_transaction_management()
-
- def is_dirty(self):
- """
- Returns True if the current transaction requires a commit for changes to
- happen.
- """
- return self._dirty
-
- def set_dirty(self):
- """
- Sets a dirty flag for the current thread and code streak. This can be used
- to decide in a managed block of code to decide whether there are open
- changes waiting for commit.
- """
- if not self.get_autocommit():
- self._dirty = True
-
- def set_clean(self):
- """
- Resets a dirty flag for the current thread and code streak. This can be used
- to decide in a managed block of code to decide whether a commit or rollback
- should happen.
- """
- self._dirty = False
- self.clean_savepoints()
-
##### Foreign key constraints checks handling #####
@contextmanager
@@ -576,10 +482,6 @@ class BaseDatabaseFeatures(object):
# at the end of each save operation?
supports_forward_references = True
- # Does a dirty transaction need to be rolled back
- # before the cursor can be used again?
- requires_rollback_on_dirty_transaction = False
-
# Does the backend allow very long model names without error?
supports_long_model_names = True
@@ -682,28 +584,21 @@ def __init__(self, connection):
@cached_property
def supports_transactions(self):
- "Confirm support for transactions"
- try:
- # Make sure to run inside a managed transaction block,
- # otherwise autocommit will cause the confimation to
- # fail.
- self.connection.enter_transaction_management()
- with self.connection.cursor() as cursor:
- cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
- self.connection.commit()
- cursor.execute('INSERT INTO ROLLBACK_TEST (X) VALUES (8)')
- self.connection.rollback()
- cursor.execute('SELECT COUNT(X) FROM ROLLBACK_TEST')
- count, = cursor.fetchone()
- cursor.execute('DROP TABLE ROLLBACK_TEST')
- self.connection.commit()
- finally:
- self.connection.leave_transaction_management()
+ """Confirm support for transactions."""
+ with self.connection.cursor() as cursor:
+ cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
+ self.connection.set_autocommit(False)
+ cursor.execute('INSERT INTO ROLLBACK_TEST (X) VALUES (8)')
+ self.connection.rollback()
+ self.connection.set_autocommit(True)
+ cursor.execute('SELECT COUNT(X) FROM ROLLBACK_TEST')
+ count, = cursor.fetchone()
+ cursor.execute('DROP TABLE ROLLBACK_TEST')
return count == 0
@cached_property
def supports_stddev(self):
- "Confirm support for STDDEV and related stats functions"
+ """Confirm support for STDDEV and related stats functions."""
class StdDevPop(object):
sql_function = 'STDDEV_POP'
@@ -67,8 +67,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
_savepoint_commit = complain
_savepoint_rollback = ignore
_set_autocommit = complain
- set_dirty = complain
- set_clean = complain
def __init__(self, *args, **kwargs):
super(DatabaseWrapper, self).__init__(*args, **kwargs)
@@ -48,7 +48,6 @@ def utc_tzinfo_factory(offset):
class DatabaseFeatures(BaseDatabaseFeatures):
needs_datetime_string_cast = False
can_return_id_from_insert = True
- requires_rollback_on_dirty_transaction = True
has_real_datatype = True
can_defer_constraint_checks = True
has_select_for_update = True
@@ -181,8 +180,6 @@ def close(self):
exc_info=sys.exc_info()
)
raise
- finally:
- self.set_clean()
def _set_isolation_level(self, isolation_level):
assert isolation_level in range(1, 5) # Use set_autocommit for level = 0
@@ -44,7 +44,6 @@ def __exit__(self, type, value, traceback):
def callproc(self, procname, params=None):
self.db.validate_no_broken_transaction()
- self.db.set_dirty()
with self.db.wrap_database_errors:
if params is None:
return self.cursor.callproc(procname)
@@ -53,7 +52,6 @@ def callproc(self, procname, params=None):
def execute(self, sql, params=None):
self.db.validate_no_broken_transaction()
- self.db.set_dirty()
with self.db.wrap_database_errors:
if params is None:
return self.cursor.execute(sql)
@@ -62,7 +60,6 @@ def execute(self, sql, params=None):
def executemany(self, sql, param_list):
self.db.validate_no_broken_transaction()
- self.db.set_dirty()
with self.db.wrap_database_errors:
return self.cursor.executemany(sql, param_list)
@@ -625,7 +625,7 @@ def save_base(self, raw=False, force_insert=False,
if not meta.auto_created:
signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using,
update_fields=update_fields)
- with transaction.commit_on_success_unless_managed(using=using, savepoint=False):
+ with transaction.atomic(using=using, savepoint=False):
if not raw:
self._save_parents(cls, using, update_fields)
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
@@ -1417,7 +1417,7 @@ def method_set_order(ordered_obj, self, id_list, using=None):
order_name = ordered_obj._meta.order_with_respect_to.name
# FIXME: It would be nice if there was an "update many" version of update
# for situations like this.
- with transaction.commit_on_success_unless_managed(using=using):
+ with transaction.atomic(using=using, savepoint=False):
for i, j in enumerate(id_list):
ordered_obj.objects.filter(**{'pk': j, order_name: rel_val}).update(_order=i)
Oops, something went wrong.

0 comments on commit 0f95608

Please sign in to comment.