mirror of
https://github.com/django/django.git
synced 2024-12-01 15:42:04 +01:00
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
|
||||
|
||||
# Transaction management related attributes
|
||||
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
|
||||
@ -232,6 +233,12 @@ class BaseDatabaseWrapper(object):
|
||||
"""
|
||||
pass
|
||||
|
||||
def _set_autocommit(self, autocommit):
|
||||
"""
|
||||
Backend-specific implementation to enable or disable autocommit.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
##### Generic transaction management methods #####
|
||||
|
||||
def enter_transaction_management(self, managed=True, forced=False):
|
||||
@ -274,6 +281,13 @@ class BaseDatabaseWrapper(object):
|
||||
raise TransactionManagementError(
|
||||
"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):
|
||||
"""
|
||||
Roll back any ongoing transaction and clean the transaction state
|
||||
|
@ -1,6 +1,7 @@
|
||||
import hashlib
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
|
||||
from django.conf import settings
|
||||
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
|
||||
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):
|
||||
"""
|
||||
|
@ -57,6 +57,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
_savepoint_rollback = ignore
|
||||
_enter_transaction_management = complain
|
||||
_leave_transaction_management = ignore
|
||||
_set_autocommit = complain
|
||||
set_dirty = complain
|
||||
set_clean = complain
|
||||
commit_unless_managed = complain
|
||||
|
@ -445,6 +445,9 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
except Database.NotSupportedError:
|
||||
pass
|
||||
|
||||
def _set_autocommit(self, autocommit):
|
||||
self.connection.autocommit(autocommit)
|
||||
|
||||
def disable_constraint_checking(self):
|
||||
"""
|
||||
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):
|
||||
pass
|
||||
|
||||
def _set_autocommit(self, autocommit):
|
||||
self.connection.autocommit = autocommit
|
||||
|
||||
def check_constraints(self, table_names=None):
|
||||
"""
|
||||
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'],
|
||||
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.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):
|
||||
if ((self.transaction_state and self.transaction_state[-1]) or
|
||||
not self.features.uses_autocommit):
|
||||
|
@ -78,9 +78,6 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||
' text_pattern_ops'))
|
||||
return output
|
||||
|
||||
def set_autocommit(self):
|
||||
self._prepare_for_test_db_ddl()
|
||||
|
||||
def _prepare_for_test_db_ddl(self):
|
||||
"""Rollback and close the active transaction."""
|
||||
# Make sure there is an open connection.
|
||||
|
@ -355,6 +355,17 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
if self.settings_dict['NAME'] != ":memory:":
|
||||
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):
|
||||
"""
|
||||
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
|
||||
os.remove(test_database_name)
|
||||
|
||||
def set_autocommit(self):
|
||||
self.connection.connection.isolation_level = None
|
||||
|
||||
def test_db_signature(self):
|
||||
"""
|
||||
Returns a tuple that uniquely identifies a test database.
|
||||
|
@ -39,6 +39,18 @@ def get_connection(using=None):
|
||||
using = DEFAULT_DB_ALIAS
|
||||
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):
|
||||
"""
|
||||
Roll back any ongoing transactions and clean the transaction management
|
||||
|
@ -63,6 +63,7 @@ def to_list(value):
|
||||
value = [value]
|
||||
return value
|
||||
|
||||
real_set_autocommit = transaction.set_autocommit
|
||||
real_commit = transaction.commit
|
||||
real_rollback = transaction.rollback
|
||||
real_enter_transaction_management = transaction.enter_transaction_management
|
||||
@ -73,6 +74,7 @@ def nop(*args, **kwargs):
|
||||
return
|
||||
|
||||
def disable_transaction_methods():
|
||||
transaction.set_autocommit = nop
|
||||
transaction.commit = nop
|
||||
transaction.rollback = nop
|
||||
transaction.enter_transaction_management = nop
|
||||
@ -80,6 +82,7 @@ def disable_transaction_methods():
|
||||
transaction.abort = nop
|
||||
|
||||
def restore_transaction_methods():
|
||||
transaction.set_autocommit = real_set_autocommit
|
||||
transaction.commit = real_commit
|
||||
transaction.rollback = real_rollback
|
||||
transaction.enter_transaction_management = real_enter_transaction_management
|
||||
|
@ -348,9 +348,10 @@ these changes.
|
||||
* Remove the backward compatible shims introduced to rename the attributes
|
||||
``ChangeList.root_query_set`` and ``ChangeList.query_set``.
|
||||
|
||||
* The private API ``django.db.close_connection`` will be removed.
|
||||
|
||||
* The private API ``django.transaction.managed`` will be removed.
|
||||
* The following private APIs will be removed:
|
||||
- ``django.db.close_connection()``
|
||||
- ``django.db.backends.creation.BaseDatabaseCreation.set_autocommit()``
|
||||
- ``django.db.transaction.managed()``
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
How to globally deactivate transaction management
|
||||
|
Loading…
Reference in New Issue
Block a user