mirror of https://github.com/django/django.git
Added an API to control database-level autocommit.
This commit is contained in:
parent
7aacde84f2
commit
f515619494
|
@ -44,6 +44,7 @@ class BaseDatabaseWrapper(object):
|
||||||
self.savepoint_state = 0
|
self.savepoint_state = 0
|
||||||
|
|
||||||
# Transaction management related attributes
|
# Transaction management related attributes
|
||||||
|
self.autocommit = False
|
||||||
self.transaction_state = []
|
self.transaction_state = []
|
||||||
# Tracks if the connection is believed to be in transaction. This is
|
# Tracks if the connection is believed to be in transaction. This is
|
||||||
# set somewhat aggressively, as the DBAPI doesn't make it easy to
|
# set somewhat aggressively, as the DBAPI doesn't make it easy to
|
||||||
|
@ -232,6 +233,12 @@ class BaseDatabaseWrapper(object):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _set_autocommit(self, autocommit):
|
||||||
|
"""
|
||||||
|
Backend-specific implementation to enable or disable autocommit.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
##### Generic transaction management methods #####
|
##### Generic transaction management methods #####
|
||||||
|
|
||||||
def enter_transaction_management(self, managed=True, forced=False):
|
def enter_transaction_management(self, managed=True, forced=False):
|
||||||
|
@ -274,6 +281,13 @@ class BaseDatabaseWrapper(object):
|
||||||
raise TransactionManagementError(
|
raise TransactionManagementError(
|
||||||
"Transaction managed block ended with pending COMMIT/ROLLBACK")
|
"Transaction managed block ended with pending COMMIT/ROLLBACK")
|
||||||
|
|
||||||
|
def set_autocommit(self, autocommit=True):
|
||||||
|
"""
|
||||||
|
Enable or disable autocommit.
|
||||||
|
"""
|
||||||
|
self._set_autocommit(autocommit)
|
||||||
|
self.autocommit = autocommit
|
||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
"""
|
"""
|
||||||
Roll back any ongoing transaction and clean the transaction state
|
Roll back any ongoing transaction and clean the transaction state
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import warnings
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.utils import load_backend
|
from django.db.utils import load_backend
|
||||||
|
@ -466,7 +467,10 @@ class BaseDatabaseCreation(object):
|
||||||
anymore by Django code. Kept for compatibility with user code that
|
anymore by Django code. Kept for compatibility with user code that
|
||||||
might use it.
|
might use it.
|
||||||
"""
|
"""
|
||||||
pass
|
warnings.warn(
|
||||||
|
"set_autocommit was moved from BaseDatabaseCreation to "
|
||||||
|
"BaseDatabaseWrapper.", PendingDeprecationWarning, stacklevel=2)
|
||||||
|
return self.connection.set_autocommit()
|
||||||
|
|
||||||
def _prepare_for_test_db_ddl(self):
|
def _prepare_for_test_db_ddl(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -57,6 +57,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
_savepoint_rollback = ignore
|
_savepoint_rollback = ignore
|
||||||
_enter_transaction_management = complain
|
_enter_transaction_management = complain
|
||||||
_leave_transaction_management = ignore
|
_leave_transaction_management = ignore
|
||||||
|
_set_autocommit = complain
|
||||||
set_dirty = complain
|
set_dirty = complain
|
||||||
set_clean = complain
|
set_clean = complain
|
||||||
commit_unless_managed = complain
|
commit_unless_managed = complain
|
||||||
|
|
|
@ -445,6 +445,9 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
except Database.NotSupportedError:
|
except Database.NotSupportedError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _set_autocommit(self, autocommit):
|
||||||
|
self.connection.autocommit(autocommit)
|
||||||
|
|
||||||
def disable_constraint_checking(self):
|
def disable_constraint_checking(self):
|
||||||
"""
|
"""
|
||||||
Disables foreign key checks, primarily for use in adding rows with forward references. Always returns True,
|
Disables foreign key checks, primarily for use in adding rows with forward references. Always returns True,
|
||||||
|
|
|
@ -612,6 +612,9 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
def _savepoint_commit(self, sid):
|
def _savepoint_commit(self, sid):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _set_autocommit(self, autocommit):
|
||||||
|
self.connection.autocommit = autocommit
|
||||||
|
|
||||||
def check_constraints(self, table_names=None):
|
def check_constraints(self, table_names=None):
|
||||||
"""
|
"""
|
||||||
To check constraints, we set constraints to immediate. Then, when, we're done we must ensure they
|
To check constraints, we set constraints to immediate. Then, when, we're done we must ensure they
|
||||||
|
|
|
@ -273,6 +273,3 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
settings_dict['NAME'],
|
settings_dict['NAME'],
|
||||||
self._test_database_user(),
|
self._test_database_user(),
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_autocommit(self):
|
|
||||||
self.connection.connection.autocommit = True
|
|
||||||
|
|
|
@ -201,6 +201,14 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
self.isolation_level = level
|
self.isolation_level = level
|
||||||
self.features.uses_savepoints = bool(level)
|
self.features.uses_savepoints = bool(level)
|
||||||
|
|
||||||
|
def _set_autocommit(self, autocommit):
|
||||||
|
if autocommit:
|
||||||
|
level = psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT
|
||||||
|
else:
|
||||||
|
level = self.settings_dict["OPTIONS"].get('isolation_level',
|
||||||
|
psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
|
||||||
|
self._set_isolation_level(level)
|
||||||
|
|
||||||
def set_dirty(self):
|
def set_dirty(self):
|
||||||
if ((self.transaction_state and self.transaction_state[-1]) or
|
if ((self.transaction_state and self.transaction_state[-1]) or
|
||||||
not self.features.uses_autocommit):
|
not self.features.uses_autocommit):
|
||||||
|
|
|
@ -78,9 +78,6 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
' text_pattern_ops'))
|
' text_pattern_ops'))
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def set_autocommit(self):
|
|
||||||
self._prepare_for_test_db_ddl()
|
|
||||||
|
|
||||||
def _prepare_for_test_db_ddl(self):
|
def _prepare_for_test_db_ddl(self):
|
||||||
"""Rollback and close the active transaction."""
|
"""Rollback and close the active transaction."""
|
||||||
# Make sure there is an open connection.
|
# Make sure there is an open connection.
|
||||||
|
|
|
@ -355,6 +355,17 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
if self.settings_dict['NAME'] != ":memory:":
|
if self.settings_dict['NAME'] != ":memory:":
|
||||||
BaseDatabaseWrapper.close(self)
|
BaseDatabaseWrapper.close(self)
|
||||||
|
|
||||||
|
def _set_autocommit(self, autocommit):
|
||||||
|
if autocommit:
|
||||||
|
level = None
|
||||||
|
else:
|
||||||
|
# sqlite3's internal default is ''. It's different from None.
|
||||||
|
# See Modules/_sqlite/connection.c.
|
||||||
|
level = ''
|
||||||
|
# 'isolation_level' is a misleading API.
|
||||||
|
# SQLite always runs at the SERIALIZABLE isolation level.
|
||||||
|
self.connection.isolation_level = level
|
||||||
|
|
||||||
def check_constraints(self, table_names=None):
|
def check_constraints(self, table_names=None):
|
||||||
"""
|
"""
|
||||||
Checks each table name in `table_names` for rows with invalid foreign key references. This method is
|
Checks each table name in `table_names` for rows with invalid foreign key references. This method is
|
||||||
|
|
|
@ -72,9 +72,6 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
# Remove the SQLite database file
|
# Remove the SQLite database file
|
||||||
os.remove(test_database_name)
|
os.remove(test_database_name)
|
||||||
|
|
||||||
def set_autocommit(self):
|
|
||||||
self.connection.connection.isolation_level = None
|
|
||||||
|
|
||||||
def test_db_signature(self):
|
def test_db_signature(self):
|
||||||
"""
|
"""
|
||||||
Returns a tuple that uniquely identifies a test database.
|
Returns a tuple that uniquely identifies a test database.
|
||||||
|
|
|
@ -39,6 +39,18 @@ def get_connection(using=None):
|
||||||
using = DEFAULT_DB_ALIAS
|
using = DEFAULT_DB_ALIAS
|
||||||
return connections[using]
|
return connections[using]
|
||||||
|
|
||||||
|
def get_autocommit(using=None):
|
||||||
|
"""
|
||||||
|
Get the autocommit status of the connection.
|
||||||
|
"""
|
||||||
|
return get_connection(using).autocommit
|
||||||
|
|
||||||
|
def set_autocommit(using=None, autocommit=True):
|
||||||
|
"""
|
||||||
|
Set the autocommit status of the connection.
|
||||||
|
"""
|
||||||
|
return get_connection(using).set_autocommit(autocommit)
|
||||||
|
|
||||||
def abort(using=None):
|
def abort(using=None):
|
||||||
"""
|
"""
|
||||||
Roll back any ongoing transactions and clean the transaction management
|
Roll back any ongoing transactions and clean the transaction management
|
||||||
|
|
|
@ -63,6 +63,7 @@ def to_list(value):
|
||||||
value = [value]
|
value = [value]
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
real_set_autocommit = transaction.set_autocommit
|
||||||
real_commit = transaction.commit
|
real_commit = transaction.commit
|
||||||
real_rollback = transaction.rollback
|
real_rollback = transaction.rollback
|
||||||
real_enter_transaction_management = transaction.enter_transaction_management
|
real_enter_transaction_management = transaction.enter_transaction_management
|
||||||
|
@ -73,6 +74,7 @@ def nop(*args, **kwargs):
|
||||||
return
|
return
|
||||||
|
|
||||||
def disable_transaction_methods():
|
def disable_transaction_methods():
|
||||||
|
transaction.set_autocommit = nop
|
||||||
transaction.commit = nop
|
transaction.commit = nop
|
||||||
transaction.rollback = nop
|
transaction.rollback = nop
|
||||||
transaction.enter_transaction_management = nop
|
transaction.enter_transaction_management = nop
|
||||||
|
@ -80,6 +82,7 @@ def disable_transaction_methods():
|
||||||
transaction.abort = nop
|
transaction.abort = nop
|
||||||
|
|
||||||
def restore_transaction_methods():
|
def restore_transaction_methods():
|
||||||
|
transaction.set_autocommit = real_set_autocommit
|
||||||
transaction.commit = real_commit
|
transaction.commit = real_commit
|
||||||
transaction.rollback = real_rollback
|
transaction.rollback = real_rollback
|
||||||
transaction.enter_transaction_management = real_enter_transaction_management
|
transaction.enter_transaction_management = real_enter_transaction_management
|
||||||
|
|
|
@ -348,9 +348,10 @@ these changes.
|
||||||
* Remove the backward compatible shims introduced to rename the attributes
|
* Remove the backward compatible shims introduced to rename the attributes
|
||||||
``ChangeList.root_query_set`` and ``ChangeList.query_set``.
|
``ChangeList.root_query_set`` and ``ChangeList.query_set``.
|
||||||
|
|
||||||
* The private API ``django.db.close_connection`` will be removed.
|
* The following private APIs will be removed:
|
||||||
|
- ``django.db.close_connection()``
|
||||||
* The private API ``django.transaction.managed`` will be removed.
|
- ``django.db.backends.creation.BaseDatabaseCreation.set_autocommit()``
|
||||||
|
- ``django.db.transaction.managed()``
|
||||||
|
|
||||||
2.0
|
2.0
|
||||||
---
|
---
|
||||||
|
|
|
@ -208,6 +208,23 @@ This applies to all database operations, not just write operations. Even
|
||||||
if your transaction only reads from the database, the transaction must
|
if your transaction only reads from the database, the transaction must
|
||||||
be committed or rolled back before you complete a request.
|
be committed or rolled back before you complete a request.
|
||||||
|
|
||||||
|
.. _managing-autocommit:
|
||||||
|
|
||||||
|
Managing autocommit
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
|
||||||
|
Django provides a straightforward API to manage the autocommit state of each
|
||||||
|
database connection, if you need to.
|
||||||
|
|
||||||
|
.. function:: get_autocommit(using=None)
|
||||||
|
|
||||||
|
.. function:: set_autocommit(using=None, autocommit=True)
|
||||||
|
|
||||||
|
These functions take a ``using`` argument which should be the name of a
|
||||||
|
database. If it isn't provided, Django uses the ``"default"`` database.
|
||||||
|
|
||||||
.. _deactivate-transaction-management:
|
.. _deactivate-transaction-management:
|
||||||
|
|
||||||
How to globally deactivate transaction management
|
How to globally deactivate transaction management
|
||||||
|
|
Loading…
Reference in New Issue