mirror of https://github.com/django/django.git
Fixed #21553 -- Ensured unusable database connections get closed.
This commit is contained in:
parent
2791fbf59d
commit
5f2f47fdfc
|
@ -351,9 +351,14 @@ class BaseDatabaseWrapper(object):
|
||||||
def is_usable(self):
|
def is_usable(self):
|
||||||
"""
|
"""
|
||||||
Tests if the database connection is usable.
|
Tests if the database connection is usable.
|
||||||
|
|
||||||
This function may assume that self.connection is not None.
|
This function may assume that self.connection is not None.
|
||||||
|
|
||||||
|
Actual implementations should take care not to raise exceptions
|
||||||
|
as that may prevent Django from recycling unusable connections.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('subclasses of BaseDatabaseWrapper may require an is_usable() method')
|
raise NotImplementedError(
|
||||||
|
"subclasses of BaseDatabaseWrapper may require an is_usable() method")
|
||||||
|
|
||||||
def close_if_unusable_or_obsolete(self):
|
def close_if_unusable_or_obsolete(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -552,7 +552,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
def is_usable(self):
|
def is_usable(self):
|
||||||
try:
|
try:
|
||||||
self.connection.ping()
|
self.connection.ping()
|
||||||
except DatabaseError:
|
except Database.Error:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -704,7 +704,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
else:
|
else:
|
||||||
# Use a cx_Oracle cursor directly, bypassing Django's utilities.
|
# Use a cx_Oracle cursor directly, bypassing Django's utilities.
|
||||||
self.connection.cursor().execute("SELECT 1 FROM DUAL")
|
self.connection.cursor().execute("SELECT 1 FROM DUAL")
|
||||||
except DatabaseError:
|
except Database.Error:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -210,7 +210,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
try:
|
try:
|
||||||
# Use a psycopg cursor directly, bypassing Django's utilities.
|
# Use a psycopg cursor directly, bypassing Django's utilities.
|
||||||
self.connection.cursor().execute("SELECT 1")
|
self.connection.cursor().execute("SELECT 1")
|
||||||
except DatabaseError:
|
except Database.Error:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -665,6 +665,37 @@ class BackendTestCase(TestCase):
|
||||||
self.assertTrue(cursor.closed)
|
self.assertTrue(cursor.closed)
|
||||||
|
|
||||||
|
|
||||||
|
class IsUsableTests(TransactionTestCase):
|
||||||
|
# Avoid using a regular TestCase because Django really dislikes closing
|
||||||
|
# the database connection inside a transaction at this point (#21202).
|
||||||
|
|
||||||
|
available_apps = []
|
||||||
|
|
||||||
|
# Unfortunately with sqlite3 the in-memory test database cannot be closed.
|
||||||
|
@skipUnlessDBFeature('test_db_allows_multiple_connections')
|
||||||
|
def test_is_usable_after_database_disconnects(self):
|
||||||
|
"""
|
||||||
|
Test that is_usable() doesn't crash when the database disconnects.
|
||||||
|
|
||||||
|
Regression for #21553.
|
||||||
|
"""
|
||||||
|
# Open a connection to the database.
|
||||||
|
with connection.cursor():
|
||||||
|
pass
|
||||||
|
# Emulate a connection close by the database.
|
||||||
|
connection._close()
|
||||||
|
# Even then is_usable() should not raise an exception.
|
||||||
|
try:
|
||||||
|
self.assertFalse(connection.is_usable())
|
||||||
|
finally:
|
||||||
|
# Clean up the mess created by connection._close(). Since the
|
||||||
|
# connection is already closed, this crashes on some backends.
|
||||||
|
try:
|
||||||
|
connection.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# We don't make these tests conditional because that means we would need to
|
# We don't make these tests conditional because that means we would need to
|
||||||
# check and differentiate between:
|
# check and differentiate between:
|
||||||
# * MySQL+InnoDB, MySQL+MYISAM (something we currently can't do).
|
# * MySQL+InnoDB, MySQL+MYISAM (something we currently can't do).
|
||||||
|
|
Loading…
Reference in New Issue