summaryrefslogtreecommitdiff
path: root/django/db
diff options
context:
space:
mode:
Diffstat (limited to 'django/db')
-rw-r--r--django/db/__init__.py13
-rw-r--r--django/db/backends/__init__.py11
-rw-r--r--django/db/transaction.py15
-rw-r--r--django/db/utils.py3
4 files changed, 40 insertions, 2 deletions
diff --git a/django/db/__init__.py b/django/db/__init__.py
index b1980488df..94eca13d41 100644
--- a/django/db/__init__.py
+++ b/django/db/__init__.py
@@ -42,8 +42,17 @@ backend = load_backend(connection.settings_dict['ENGINE'])
# Register an event that closes the database connection
# when a Django request is finished.
def close_connection(**kwargs):
- for conn in connections.all():
- conn.close()
+ # Avoid circular imports
+ from django.db import transaction
+ for conn in connections:
+ try:
+ transaction.abort(conn)
+ connections[conn].close()
+ except Exception:
+ # The connection's state is unknown, so it has to be
+ # abandoned. This could happen for example if the network
+ # connection has a failure.
+ del connections[conn]
signals.request_finished.connect(close_connection)
# Register an event that resets connection.queries
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 7dc5456827..bbb5a5b294 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -88,6 +88,17 @@ class BaseDatabaseWrapper(object):
return
self.cursor().execute(self.ops.savepoint_commit_sql(sid))
+ def abort(self):
+ """
+ Roll back any ongoing transaction and clean the transaction state
+ stack.
+ """
+ if self._dirty:
+ self._rollback()
+ self._dirty = False
+ while self.transaction_state:
+ self.leave_transaction_management()
+
def enter_transaction_management(self, managed=True):
"""
Enters transaction management for a running thread. It must be balanced with
diff --git a/django/db/transaction.py b/django/db/transaction.py
index f3ce2b2335..dd7e2f4dcb 100644
--- a/django/db/transaction.py
+++ b/django/db/transaction.py
@@ -24,6 +24,21 @@ class TransactionManagementError(Exception):
"""
pass
+def abort(using=None):
+ """
+ Roll back any ongoing transactions and clean the transaction management
+ state of the connection.
+
+ This method is to be used only in cases where using balanced
+ leave_transaction_management() calls isn't possible. For example after a
+ request has finished, the transaction state isn't known, yet the connection
+ must be cleaned up for the next request.
+ """
+ if using is None:
+ using = DEFAULT_DB_ALIAS
+ connection = connections[using]
+ connection.abort()
+
def enter_transaction_management(managed=True, using=None):
"""
Enters transaction management for a running thread. It must be balanced with
diff --git a/django/db/utils.py b/django/db/utils.py
index 91fa774ed4..943e3e3f73 100644
--- a/django/db/utils.py
+++ b/django/db/utils.py
@@ -99,6 +99,9 @@ class ConnectionHandler(object):
def __setitem__(self, key, value):
setattr(self._connections, key, value)
+ def __delitem__(self, key):
+ delattr(self._connections, key)
+
def __iter__(self):
return iter(self.databases)