1
0
mirror of https://github.com/django/django.git synced 2025-10-31 09:41:08 +00:00

Fixed #7732 -- Added support for connection pools on Oracle.

This commit is contained in:
suraj
2024-09-10 20:56:16 +05:30
committed by Sarah Boyce
parent 2249370c86
commit 0d9872fc9a
7 changed files with 215 additions and 9 deletions

View File

@@ -14,6 +14,7 @@ from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db import IntegrityError
from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.backends.oracle.oracledb_any import is_oracledb
from django.db.backends.utils import debug_transaction
from django.utils.asyncio import async_unsafe
from django.utils.encoding import force_bytes, force_str
@@ -235,6 +236,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
introspection_class = DatabaseIntrospection
ops_class = DatabaseOperations
validation_class = DatabaseValidation
_connection_pools = {}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -243,10 +245,52 @@ class DatabaseWrapper(BaseDatabaseWrapper):
)
self.features.can_return_columns_from_insert = use_returning_into
@property
def is_pool(self):
return self.settings_dict["OPTIONS"].get("pool", False)
@property
def pool(self):
if not self.is_pool:
return None
if self.settings_dict.get("CONN_MAX_AGE", 0) != 0:
raise ImproperlyConfigured(
"Pooling doesn't support persistent connections."
)
pool_key = (self.alias, self.settings_dict["USER"])
if pool_key not in self._connection_pools:
connect_kwargs = self.get_connection_params()
pool_options = connect_kwargs.pop("pool")
if pool_options is not True:
connect_kwargs.update(pool_options)
pool = Database.create_pool(
user=self.settings_dict["USER"],
password=self.settings_dict["PASSWORD"],
dsn=dsn(self.settings_dict),
**connect_kwargs,
)
self._connection_pools.setdefault(pool_key, pool)
return self._connection_pools[pool_key]
def close_pool(self):
if self.pool:
self.pool.close(force=True)
pool_key = (self.alias, self.settings_dict["USER"])
del self._connection_pools[pool_key]
def get_database_version(self):
return self.oracle_version
def get_connection_params(self):
# Pooling feature is only supported for oracledb.
if self.is_pool and not is_oracledb:
raise ImproperlyConfigured(
"Pooling isn't supported by cx_Oracle. Use python-oracledb instead."
)
conn_params = self.settings_dict["OPTIONS"].copy()
if "use_returning_into" in conn_params:
del conn_params["use_returning_into"]
@@ -254,6 +298,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
@async_unsafe
def get_new_connection(self, conn_params):
if self.pool:
return self.pool.acquire()
return Database.connect(
user=self.settings_dict["USER"],
password=self.settings_dict["PASSWORD"],
@@ -345,6 +391,12 @@ class DatabaseWrapper(BaseDatabaseWrapper):
else:
return True
def close_if_health_check_failed(self):
if self.pool:
# The pool only returns healthy connections.
return
return super().close_if_health_check_failed()
@cached_property
def oracle_version(self):
with self.temporary_connection():

View File

@@ -205,13 +205,15 @@ class DatabaseCreation(BaseDatabaseCreation):
Destroy a test database, prompting the user for confirmation if the
database already exists. Return the name of the test database created.
"""
self.connection.settings_dict["USER"] = self.connection.settings_dict[
"SAVED_USER"
]
self.connection.settings_dict["PASSWORD"] = self.connection.settings_dict[
"SAVED_PASSWORD"
]
if not self.connection.is_pool:
self.connection.settings_dict["USER"] = self.connection.settings_dict[
"SAVED_USER"
]
self.connection.settings_dict["PASSWORD"] = self.connection.settings_dict[
"SAVED_PASSWORD"
]
self.connection.close()
self.connection.close_pool()
parameters = self._get_test_db_params()
with self._maindb_connection.cursor() as cursor:
if self._test_user_create():
@@ -223,6 +225,7 @@ class DatabaseCreation(BaseDatabaseCreation):
self.log("Destroying test database tables...")
self._execute_test_db_destruction(cursor, parameters, verbosity)
self._maindb_connection.close()
self._maindb_connection.close_pool()
def _execute_test_db_creation(self, cursor, parameters, verbosity, keepdb=False):
if verbosity >= 2:

View File

@@ -139,6 +139,25 @@ class DatabaseFeatures(BaseDatabaseFeatures):
},
}
)
if self.connection.is_pool:
skips.update(
{
"Pooling does not support persistent connections": {
"backends.base.test_base.ConnectionHealthChecksTests."
"test_health_checks_enabled",
"backends.base.test_base.ConnectionHealthChecksTests."
"test_health_checks_enabled_errors_occurred",
"backends.base.test_base.ConnectionHealthChecksTests."
"test_health_checks_disabled",
"backends.base.test_base.ConnectionHealthChecksTests."
"test_set_autocommit_health_checks_enabled",
"servers.tests.LiveServerTestCloseConnectionTest."
"test_closes_connections",
"backends.oracle.tests.TransactionalTests."
"test_password_with_at_sign",
},
}
)
if is_oracledb and self.connection.oracledb_version >= (2, 1, 2):
skips.update(
{