Index: django/db/transaction/fast_select.py
===================================================================
--- django/db/transaction/fast_select.py	(revision 0)
+++ django/db/transaction/fast_select.py	(working copy)
@@ -10,31 +10,27 @@
 
 Managed transactions don't do those commits, but will need some kind of manual
 or implicit commits or rollbacks.
+
+This is a version of the transaction manager which marks transactions
+as 'clean' or 'dirty', and neglects to close 'clean' transactions to
+improve performnce.
+
+TODO: Explain when this breaks, and when it is less efficient
 """
 
+
 try:
     import thread
 except ImportError:
     import dummy_thread as thread
-try:
-    from functools import wraps
-except ImportError:
-    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
+
 from django.db import connection
 from django.conf import settings
 
-class TransactionManagementError(Exception):
-    """
-    This exception is thrown when something bad happens with transaction
-    management.
-    """
-    pass
+from django.db.transaction import TransactionManagementError
+from django.db.transaction import state, savepoint_state
+from django.db.transaction import is_managed, clean_savepoints, rollback
 
-# The states are dictionaries of lists. The key to the dict is the current
-# thread and the list is handled as a stack of values.
-state = {}
-savepoint_state = {}
-
 # The dirty flag is set by *_unless_managed functions to denote that the
 # code under transaction management has changed things to require a
 # database commit.
@@ -109,161 +105,3 @@
         raise TransactionManagementError("This code isn't under transaction management")
     clean_savepoints()
 
-def clean_savepoints():
-    thread_ident = thread.get_ident()
-    if thread_ident in savepoint_state:
-        del savepoint_state[thread_ident]
-
-def is_managed():
-    """
-    Checks whether the transaction manager is in manual or in auto state.
-    """
-    thread_ident = thread.get_ident()
-    if thread_ident in state:
-        if state[thread_ident]:
-            return state[thread_ident][-1]
-    return settings.TRANSACTIONS_MANAGED
-
-def managed(flag=True):
-    """
-    Puts the transaction manager into a manual state: managed transactions have
-    to be committed explicitly by the user. If you switch off transaction
-    management and there is a pending commit/rollback, the data will be
-    commited.
-    """
-    thread_ident = thread.get_ident()
-    top = state.get(thread_ident, None)
-    if top:
-        top[-1] = flag
-        if not flag and is_dirty():
-            connection._commit()
-            set_clean()
-    else:
-        raise TransactionManagementError("This code isn't under transaction management")
-
-def commit_unless_managed():
-    """
-    Commits changes if the system is not in managed transaction mode.
-    """
-    if not is_managed():
-        connection._commit()
-        clean_savepoints()
-    else:
-        set_dirty()
-
-def rollback_unless_managed():
-    """
-    Rolls back changes if the system is not in managed transaction mode.
-    """
-    if not is_managed():
-        connection._rollback()
-    else:
-        set_dirty()
-
-def commit():
-    """
-    Does the commit itself and resets the dirty flag.
-    """
-    connection._commit()
-    set_clean()
-
-def rollback():
-    """
-    This function does the rollback itself and resets the dirty flag.
-    """
-    connection._rollback()
-    set_clean()
-
-def savepoint():
-    """
-    Creates a savepoint (if supported and required by the backend) inside the
-    current transaction. Returns an identifier for the savepoint that will be
-    used for the subsequent rollback or commit.
-    """
-    thread_ident = thread.get_ident()
-    if thread_ident in savepoint_state:
-        savepoint_state[thread_ident].append(None)
-    else:
-        savepoint_state[thread_ident] = [None]
-    tid = str(thread_ident).replace('-', '')
-    sid = "s%s_x%d" % (tid, len(savepoint_state[thread_ident]))
-    connection._savepoint(sid)
-    return sid
-
-def savepoint_rollback(sid):
-    """
-    Rolls back the most recent savepoint (if one exists). Does nothing if
-    savepoints are not supported.
-    """
-    if thread.get_ident() in savepoint_state:
-        connection._savepoint_rollback(sid)
-
-def savepoint_commit(sid):
-    """
-    Commits the most recent savepoint (if one exists). Does nothing if
-    savepoints are not supported.
-    """
-    if thread.get_ident() in savepoint_state:
-        connection._savepoint_commit(sid)
-
-##############
-# DECORATORS #
-##############
-
-def autocommit(func):
-    """
-    Decorator that activates commit on save. This is Django's default behavior;
-    this decorator is useful if you globally activated transaction management in
-    your settings file and want the default behavior in some view functions.
-    """
-    def _autocommit(*args, **kw):
-        try:
-            enter_transaction_management(managed=False)
-            managed(False)
-            return func(*args, **kw)
-        finally:
-            leave_transaction_management()
-    return wraps(func)(_autocommit)
-
-def commit_on_success(func):
-    """
-    This decorator activates commit on response. This way, if the view function
-    runs successfully, a commit is made; if the viewfunc produces an exception,
-    a rollback is made. This is one of the most common ways to do transaction
-    control in web apps.
-    """
-    def _commit_on_success(*args, **kw):
-        try:
-            enter_transaction_management()
-            managed(True)
-            try:
-                res = func(*args, **kw)
-            except:
-                # All exceptions must be handled here (even string ones).
-                if is_dirty():
-                    rollback()
-                raise
-            else:
-                if is_dirty():
-                    commit()
-            return res
-        finally:
-            leave_transaction_management()
-    return wraps(func)(_commit_on_success)
-
-def commit_manually(func):
-    """
-    Decorator that activates manual transaction control. It just disables
-    automatic transaction control and doesn't do any commit/rollback of its
-    own -- it's up to the user to call the commit and rollback functions
-    themselves.
-    """
-    def _commit_manually(*args, **kw):
-        try:
-            enter_transaction_management()
-            managed(True)
-            return func(*args, **kw)
-        finally:
-            leave_transaction_management()
-
-    return wraps(func)(_commit_manually)
Index: django/db/transaction/safe.py
===================================================================
--- django/db/transaction/safe.py	(revision 0)
+++ django/db/transaction/safe.py	(revision 0)
@@ -0,0 +1,90 @@
+"""
+This module implements a transaction manager that can be used to define
+transaction handling in a request or view function. It is used by transaction
+control middleware and decorators.
+
+The transaction manager can be in managed or in auto state. Auto state means the
+system is using a commit-on-save strategy (actually it's more like
+commit-on-change). As soon as the .save() or .delete() (or related) methods are
+called, a commit is made.
+
+Managed transactions don't do those commits, but will need some kind of manual
+or implicit commits or rollbacks.
+
+This is a version of the transaction manager which treats all transactions
+as 'dirty', so that they are always closed.
+"""
+
+try:
+    import thread
+except ImportError:
+    import dummy_thread as thread
+try:
+    from functools import wraps
+except ImportError:
+    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
+from django.db import connection
+from django.conf import settings
+
+from django.db.transaction import TransactionManagementError
+from django.db.transaction import state, savepoint_state
+from django.db.transaction import is_managed, clean_savepoints, rollback
+
+
+def enter_transaction_management(managed=True):
+    """
+    Enters transaction management for a running thread. It must be balanced with
+    the appropriate leave_transaction_management call, since the actual state is
+    managed as a stack.
+
+    The state and dirty flag are carried over from the surrounding block or
+    from the settings, if there is no surrounding block (dirty is always false
+    when no current block is running).
+    """
+    thread_ident = thread.get_ident()
+    if thread_ident in state and state[thread_ident]:
+        state[thread_ident].append(state[thread_ident][-1])
+    else:
+        state[thread_ident] = []
+        state[thread_ident].append(settings.TRANSACTIONS_MANAGED)
+    connection._enter_transaction_management(managed)
+
+def leave_transaction_management():
+    """
+    Leaves transaction management for a running thread.
+    """
+    connection._leave_transaction_management(is_managed())
+    thread_ident = thread.get_ident()
+    if thread_ident in state and state[thread_ident]:
+        del state[thread_ident][-1]
+    else:
+        raise TransactionManagementError("This code isn't under transaction management")
+    # TODO: This has two drawbacks:
+    #  - It generates a redundant database hit in most cases
+    #  - As we no longer tell whether a transaction is dirty,
+    #    we cannot throw exceptions if a transaction is pending
+    # To go on the safe side, anything not committed should be rolled back
+    rollback()
+
+def is_dirty():
+    """
+    All transactions are always dirty
+    """
+    return True
+
+def set_dirty():
+    """
+    All transactions are always dirty
+    """
+    pass
+
+def set_clean():
+    """
+    All transactions are always dirty
+    """
+    # TODO: Really? Retained from the fast_select version
+    clean_savepoints()
+
+
+
+
Index: django/db/transaction/__init__.py
===================================================================
--- django/db/transaction/__init__.py	(revision 0)
+++ django/db/transaction/__init__.py	(revision 0)
@@ -0,0 +1,274 @@
+"""
+This module supports selection, by a setting, of a 
+transaction management "policy". Current policies
+are "fast-select" (which leaves clean transactions
+open) and "safe" (which makes sure all transactions
+are closed, whether they are committed or rolled back.
+
+TODO: Document when fast is not safe, and when fast is
+not even fast (repatable-read w/out MVCC).
+"""
+
+###############
+# Common base #
+###############
+
+# These are common to the policies
+try:
+    import thread
+except ImportError:
+    import dummy_thread as thread
+try:
+    from functools import wraps
+except ImportError:
+    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
+from django.db import connection
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+
+class TransactionManagementError(Exception):
+    """
+    This exception is thrown when something bad happens with transaction
+    management.
+    """
+    pass
+
+# The states are dictionaries of lists. The key to the dict is the current
+# thread and the list is handled as a stack of values.
+state = {}
+savepoint_state = {}
+
+def is_managed():
+    """
+    Checks whether the transaction manager is in manual or in auto state.
+    Note: True means 'managed manually', False means 'auto'
+    """
+    thread_ident = thread.get_ident()
+    if thread_ident in state:
+        if state[thread_ident]:
+            return state[thread_ident][-1]
+    return settings.TRANSACTIONS_MANAGED
+
+def managed(flag=True):
+    """
+    Puts the transaction manager into a manual state: managed transactions have
+    to be committed explicitly by the user. If you switch off transaction
+    management and there is a pending commit/rollback, the data will be
+    commited.
+    """
+    thread_ident = thread.get_ident()
+    top = state.get(thread_ident, None)
+    if top:
+        top[-1] = flag
+        if not flag and is_dirty():
+            connection._commit()
+            set_clean()
+    else:
+        raise TransactionManagementError("This code isn't under transaction management")
+
+def commit_unless_managed():
+    """
+    Commits changes if the system is not in managed transaction mode.
+    """
+    if not is_managed():
+        connection._commit()
+        clean_savepoints()
+    else:
+        set_dirty()
+
+def rollback_unless_managed():
+    """
+    Rolls back changes if the system is not in managed transaction mode.
+    """
+    if not is_managed():
+        connection._rollback()
+    else:
+        set_dirty()
+
+def commit():
+    """
+    Does the commit itself and resets the dirty flag.
+    """
+    connection._commit()
+    set_clean()
+
+def rollback():
+    """
+    This function does the rollback itself and resets the dirty flag.
+    """
+    connection._rollback()
+    set_clean()
+
+def clean_savepoints():
+    thread_ident = thread.get_ident()
+    if thread_ident in savepoint_state:
+        del savepoint_state[thread_ident]
+
+def savepoint():
+    """
+    Creates a savepoint (if supported and required by the backend) inside the
+    current transaction. Returns an identifier for the savepoint that will be
+    used for the subsequent rollback or commit.
+    """
+    thread_ident = thread.get_ident()
+    if thread_ident in savepoint_state:
+        savepoint_state[thread_ident].append(None)
+    else:
+        savepoint_state[thread_ident] = [None]
+    tid = str(thread_ident).replace('-', '')
+    sid = "s%s_x%d" % (tid, len(savepoint_state[thread_ident]))
+    connection._savepoint(sid)
+    return sid
+
+def savepoint_rollback(sid):
+    """
+    Rolls back the most recent savepoint (if one exists). Does nothing if
+    savepoints are not supported.
+    """
+    if thread.get_ident() in savepoint_state:
+        connection._savepoint_rollback(sid)
+
+def savepoint_commit(sid):
+    """
+    Commits the most recent savepoint (if one exists). Does nothing if
+    savepoints are not supported.
+    """
+    if thread.get_ident() in savepoint_state:
+        connection._savepoint_commit(sid)
+
+#####################
+# Policy controlled #
+#####################
+
+## DRY-minimizing set of functions for policy control
+
+def _get_policy_module():
+    policy = getattr(settings, 'TRANSACTION_POLICY', 'fast_select')
+    if policy=='fast_select':
+        import fast_select
+        return fast_select
+    elif policy=='safe':
+        import safe
+        return safe
+    else:
+        raise ImproperlyConfigured, "Unknown transaction policy '%s'" % str(policy)
+
+_to_be_loaded = []
+
+def _load_from_policy_module():
+    module = _get_policy_module()
+    for name in _to_be_loaded:
+        globals()[name] = getattr(module, name[1:])
+
+
+def policy_controlled(func):
+    """ 
+    For a function "func", defines a function "_func" which, when
+    first called, replaces itself with function "func" from the 
+    policy module. Thus, the implementation of func here can
+    just be written:
+    def func()
+        return _func()
+    policy_controlled(func)
+    """
+    place_holder_name = "_" + func.func_name
+    def place_holder_func(*args, **kwargs):
+        """
+        This code is only executed on the first place_holder func to be called
+        """
+        #print "policy_controlled, replacing ",place_holder_name
+        _load_from_policy_module()
+        real_func = globals()[place_holder_name]
+        return real_func(*args, **kwargs)
+    globals()[place_holder_name] = place_holder_func
+    _to_be_loaded.append(place_holder_name)
+    return func
+
+# The policy controlled functions
+
+def enter_transaction_management(managed=True):
+    return _enter_transaction_management(managed)
+policy_controlled(enter_transaction_management)
+
+def leave_transaction_management():
+    return _leave_transaction_management()
+policy_controlled(leave_transaction_management)
+
+def is_dirty():
+    return _is_dirty()
+policy_controlled(is_dirty)
+
+def set_dirty():
+    return _set_dirty()
+policy_controlled(set_dirty)
+
+def set_clean():
+    return _set_clean()
+policy_controlled(set_clean)
+
+##############
+# DECORATORS #
+##############
+
+# Decorators use the above functions, and their own code
+# doesn't need to change to reflect policy; they are
+# defined here to make sure they reference the right versions
+# of the functions they use
+
+def autocommit(func):
+    """
+    Decorator that activates commit on save. This is Django's default behavior;
+    this decorator is useful if you globally activated transaction management in
+    your settings file and want the default behavior in some view functions.
+    """
+    def _autocommit(*args, **kw):
+        try:
+            enter_transaction_management(managed=False)
+            managed(False)
+            return func(*args, **kw)
+        finally:
+            leave_transaction_management()
+    return wraps(func)(_autocommit)
+
+def commit_on_success(func):
+    """
+    This decorator activates commit on response. This way, if the view function
+    runs successfully, a commit is made; if the viewfunc produces an exception,
+    a rollback is made. This is one of the most common ways to do transaction
+    control in web apps.
+    """
+    def _commit_on_success(*args, **kw):
+        try:
+            enter_transaction_management()
+            managed(True)
+            try:
+                res = func(*args, **kw)
+            except:
+                # All exceptions must be handled here (even string ones).
+                if is_dirty():
+                    rollback()
+                raise
+            else:
+                if is_dirty():
+                    commit()
+            return res
+        finally:
+            leave_transaction_management()
+    return wraps(func)(_commit_on_success)
+
+def commit_manually(func):
+    """
+    Decorator that activates manual transaction control. It just disables
+    automatic transaction control and doesn't do any commit/rollback of its
+    own -- it's up to the user to call the commit and rollback functions
+    themselves.
+    """
+    def _commit_manually(*args, **kw):
+        try:
+            enter_transaction_management()
+            managed(True)
+            return func(*args, **kw)
+        finally:
+            leave_transaction_management()
+
+    return wraps(func)(_commit_manually)
Index: django/db/transaction.py
===================================================================
--- django/db/transaction.py	(revision 10087)
+++ django/db/transaction.py	(working copy)
@@ -1,269 +0,0 @@
-"""
-This module implements a transaction manager that can be used to define
-transaction handling in a request or view function. It is used by transaction
-control middleware and decorators.
-
-The transaction manager can be in managed or in auto state. Auto state means the
-system is using a commit-on-save strategy (actually it's more like
-commit-on-change). As soon as the .save() or .delete() (or related) methods are
-called, a commit is made.
-
-Managed transactions don't do those commits, but will need some kind of manual
-or implicit commits or rollbacks.
-"""
-
-try:
-    import thread
-except ImportError:
-    import dummy_thread as thread
-try:
-    from functools import wraps
-except ImportError:
-    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
-from django.db import connection
-from django.conf import settings
-
-class TransactionManagementError(Exception):
-    """
-    This exception is thrown when something bad happens with transaction
-    management.
-    """
-    pass
-
-# The states are dictionaries of lists. The key to the dict is the current
-# thread and the list is handled as a stack of values.
-state = {}
-savepoint_state = {}
-
-# The dirty flag is set by *_unless_managed functions to denote that the
-# code under transaction management has changed things to require a
-# database commit.
-dirty = {}
-
-def enter_transaction_management(managed=True):
-    """
-    Enters transaction management for a running thread. It must be balanced with
-    the appropriate leave_transaction_management call, since the actual state is
-    managed as a stack.
-
-    The state and dirty flag are carried over from the surrounding block or
-    from the settings, if there is no surrounding block (dirty is always false
-    when no current block is running).
-    """
-    thread_ident = thread.get_ident()
-    if thread_ident in state and state[thread_ident]:
-        state[thread_ident].append(state[thread_ident][-1])
-    else:
-        state[thread_ident] = []
-        state[thread_ident].append(settings.TRANSACTIONS_MANAGED)
-    if thread_ident not in dirty:
-        dirty[thread_ident] = False
-    connection._enter_transaction_management(managed)
-
-def leave_transaction_management():
-    """
-    Leaves transaction management for a running thread. A dirty flag is carried
-    over to the surrounding block, as a commit will commit all changes, even
-    those from outside. (Commits are on connection level.)
-    """
-    connection._leave_transaction_management(is_managed())
-    thread_ident = thread.get_ident()
-    if thread_ident in state and state[thread_ident]:
-        del state[thread_ident][-1]
-    else:
-        raise TransactionManagementError("This code isn't under transaction management")
-    if dirty.get(thread_ident, False):
-        rollback()
-        raise TransactionManagementError("Transaction managed block ended with pending COMMIT/ROLLBACK")
-    dirty[thread_ident] = False
-
-def is_dirty():
-    """
-    Returns True if the current transaction requires a commit for changes to
-    happen.
-    """
-    return dirty.get(thread.get_ident(), False)
-
-def set_dirty():
-    """
-    Sets a dirty flag for the current thread and code streak. This can be used
-    to decide in a managed block of code to decide whether there are open
-    changes waiting for commit.
-    """
-    thread_ident = thread.get_ident()
-    if thread_ident in dirty:
-        dirty[thread_ident] = True
-    else:
-        raise TransactionManagementError("This code isn't under transaction management")
-
-def set_clean():
-    """
-    Resets a dirty flag for the current thread and code streak. This can be used
-    to decide in a managed block of code to decide whether a commit or rollback
-    should happen.
-    """
-    thread_ident = thread.get_ident()
-    if thread_ident in dirty:
-        dirty[thread_ident] = False
-    else:
-        raise TransactionManagementError("This code isn't under transaction management")
-    clean_savepoints()
-
-def clean_savepoints():
-    thread_ident = thread.get_ident()
-    if thread_ident in savepoint_state:
-        del savepoint_state[thread_ident]
-
-def is_managed():
-    """
-    Checks whether the transaction manager is in manual or in auto state.
-    """
-    thread_ident = thread.get_ident()
-    if thread_ident in state:
-        if state[thread_ident]:
-            return state[thread_ident][-1]
-    return settings.TRANSACTIONS_MANAGED
-
-def managed(flag=True):
-    """
-    Puts the transaction manager into a manual state: managed transactions have
-    to be committed explicitly by the user. If you switch off transaction
-    management and there is a pending commit/rollback, the data will be
-    commited.
-    """
-    thread_ident = thread.get_ident()
-    top = state.get(thread_ident, None)
-    if top:
-        top[-1] = flag
-        if not flag and is_dirty():
-            connection._commit()
-            set_clean()
-    else:
-        raise TransactionManagementError("This code isn't under transaction management")
-
-def commit_unless_managed():
-    """
-    Commits changes if the system is not in managed transaction mode.
-    """
-    if not is_managed():
-        connection._commit()
-        clean_savepoints()
-    else:
-        set_dirty()
-
-def rollback_unless_managed():
-    """
-    Rolls back changes if the system is not in managed transaction mode.
-    """
-    if not is_managed():
-        connection._rollback()
-    else:
-        set_dirty()
-
-def commit():
-    """
-    Does the commit itself and resets the dirty flag.
-    """
-    connection._commit()
-    set_clean()
-
-def rollback():
-    """
-    This function does the rollback itself and resets the dirty flag.
-    """
-    connection._rollback()
-    set_clean()
-
-def savepoint():
-    """
-    Creates a savepoint (if supported and required by the backend) inside the
-    current transaction. Returns an identifier for the savepoint that will be
-    used for the subsequent rollback or commit.
-    """
-    thread_ident = thread.get_ident()
-    if thread_ident in savepoint_state:
-        savepoint_state[thread_ident].append(None)
-    else:
-        savepoint_state[thread_ident] = [None]
-    tid = str(thread_ident).replace('-', '')
-    sid = "s%s_x%d" % (tid, len(savepoint_state[thread_ident]))
-    connection._savepoint(sid)
-    return sid
-
-def savepoint_rollback(sid):
-    """
-    Rolls back the most recent savepoint (if one exists). Does nothing if
-    savepoints are not supported.
-    """
-    if thread.get_ident() in savepoint_state:
-        connection._savepoint_rollback(sid)
-
-def savepoint_commit(sid):
-    """
-    Commits the most recent savepoint (if one exists). Does nothing if
-    savepoints are not supported.
-    """
-    if thread.get_ident() in savepoint_state:
-        connection._savepoint_commit(sid)
-
-##############
-# DECORATORS #
-##############
-
-def autocommit(func):
-    """
-    Decorator that activates commit on save. This is Django's default behavior;
-    this decorator is useful if you globally activated transaction management in
-    your settings file and want the default behavior in some view functions.
-    """
-    def _autocommit(*args, **kw):
-        try:
-            enter_transaction_management(managed=False)
-            managed(False)
-            return func(*args, **kw)
-        finally:
-            leave_transaction_management()
-    return wraps(func)(_autocommit)
-
-def commit_on_success(func):
-    """
-    This decorator activates commit on response. This way, if the view function
-    runs successfully, a commit is made; if the viewfunc produces an exception,
-    a rollback is made. This is one of the most common ways to do transaction
-    control in web apps.
-    """
-    def _commit_on_success(*args, **kw):
-        try:
-            enter_transaction_management()
-            managed(True)
-            try:
-                res = func(*args, **kw)
-            except:
-                # All exceptions must be handled here (even string ones).
-                if is_dirty():
-                    rollback()
-                raise
-            else:
-                if is_dirty():
-                    commit()
-            return res
-        finally:
-            leave_transaction_management()
-    return wraps(func)(_commit_on_success)
-
-def commit_manually(func):
-    """
-    Decorator that activates manual transaction control. It just disables
-    automatic transaction control and doesn't do any commit/rollback of its
-    own -- it's up to the user to call the commit and rollback functions
-    themselves.
-    """
-    def _commit_manually(*args, **kw):
-        try:
-            enter_transaction_management()
-            managed(True)
-            return func(*args, **kw)
-        finally:
-            leave_transaction_management()
-
-    return wraps(func)(_commit_manually)
Index: django/conf/project_template/settings.py
===================================================================
--- django/conf/project_template/settings.py	(revision 10087)
+++ django/conf/project_template/settings.py	(working copy)
@@ -16,6 +16,9 @@
 DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
 DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
 
+
+TRANSACTION_POLICY = 'safe' # Options: 'safe','fast_select'; TODO: better doc.
+
 # Local time zone for this installation. Choices can be found here:
 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
 # although not all choices may be available on all operating systems.
Index: django/conf/global_settings.py
===================================================================
--- django/conf/global_settings.py	(revision 10087)
+++ django/conf/global_settings.py	(working copy)
@@ -131,6 +131,7 @@
 DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
 DATABASE_OPTIONS = {}          # Set to empty dictionary for default.
 
+
 # Host for sending e-mail.
 EMAIL_HOST = 'localhost'
 
@@ -282,8 +283,14 @@
 
 # Do you want to manage transactions manually?
 # Hint: you really don't!
-TRANSACTIONS_MANAGED = False
+TRANSACTIONS_MANAGED = False # False means 'automatic'
 
+# Django's policy for managed database transactions.
+# The current options are: 
+#  'safe': always end transaction at the end of request processing.
+#  'fast_select': leave "clean" transactions open for reuse; pre-1.1 behavior.
+TRANSACTION_POLICY = 'fast_select' 
+
 # The User-Agent string to use when checking for URL validity through the
 # isExistingURL validator.
 from django import get_version
Index: tests/modeltests/transactions/models.py
===================================================================
--- tests/modeltests/transactions/models.py	(revision 10087)
+++ tests/modeltests/transactions/models.py	(working copy)
@@ -86,14 +86,25 @@
 >>> Reporter.objects.all()
 [<Reporter: Ben Jones>, <Reporter: Carol Doe>]
 
-# If you forget, you'll get bad errors
+# If you forget, you'll get errors or rollbacks, depending on transaction policy
 >>> def manually_managed_mistake():
 ...     r = Reporter(first_name="David", last_name="Davidson")
 ...     r.save()
 ...     # oops, I forgot to commit/rollback!
 >>> manually_managed_mistake = transaction.commit_manually(manually_managed_mistake)
->>> manually_managed_mistake()
+>>> manually_managed_mistake()"""
+
+# Note: The above string must not include a final newline!
+
+if getattr(settings, 'TRANSACTION_POLICY', 'fast_select')!='safe':
+    __test__['API_TESTS'] += """
 Traceback (most recent call last):
     ...
 TransactionManagementError: Transaction managed block ended with pending COMMIT/ROLLBACK
 """
+else:
+    __test__['API_TESTS'] += """
+>>> Reporter.objects.all()
+[<Reporter: Ben Jones>, <Reporter: Carol Doe>]
+
+"""
Index: tests/modeltests/transaction_middleware/__init__.py
===================================================================
--- tests/modeltests/transaction_middleware/__init__.py	(revision 10080)
+++ tests/modeltests/transaction_middleware/__init__.py	(working copy)
@@ -0,0 +1 @@
+
Index: tests/modeltests/transaction_middleware/models.py
===================================================================
--- tests/modeltests/transaction_middleware/models.py	(revision 10080)
+++ tests/modeltests/transaction_middleware/models.py	(working copy)
@@ -1,10 +1,11 @@
 """
-15. Transactions
+15m. Transaction Middleware
 
-Django handles transactions in three different ways. The default is to commit
-each transaction upon a write, but you can decorate a function to get
-commit-on-success behavior. Alternatively, you can manage the transaction
-manually.
+Django's Transaction Middleware offers a simple consistent way
+to wrap every request in a transaction. The behavior is supposed
+to be equivalent to commit_on_success applied to the entire request
+processing (within the scope of the middleware, of course).
+These tests are closely related to the transaction tests, of course.
 """
 
 from django.db import models
@@ -18,6 +19,9 @@
         return u"%s %s" % (self.first_name, self.last_name)
 
 __test__ = {'API_TESTS':"""
+>>> from django.middleware.transaction import TransactionMiddleware
+>>> from django.utils.decorators import decorator_from_middleware
+>>> xact_middle = decorator_from_middleware(TransactionMiddleware)
 >>> from django.db import connection, transaction
 """}
 
@@ -53,9 +57,10 @@
 >>> Reporter.objects.all()
 [<Reporter: Alice Smith>, <Reporter: Ben Jones>]
 
-# With the commit_on_success decorator, the transaction is only comitted if the
+# With the transaction middleware (used here as a decorator), 
+# the transaction is only comitted if the
 # function doesn't throw an exception
->>> committed_on_success = transaction.commit_on_success(create_a_reporter_then_fail)
+>>> committed_on_success = xact_middle(create_a_reporter_then_fail)
 >>> committed_on_success("Carol", "Doe")
 Traceback (most recent call last):
     ...
@@ -66,34 +71,72 @@
 [<Reporter: Alice Smith>, <Reporter: Ben Jones>]
 
 # If there aren't any exceptions, the data will get saved
->>> def remove_a_reporter():
-...     r = Reporter.objects.get(first_name="Alice")
+>>> def remove_a_reporter(first):
+...     r = Reporter.objects.get(first_name=first)
 ...     r.delete()
 ...
->>> remove_comitted_on_success = transaction.commit_on_success(remove_a_reporter)
->>> remove_comitted_on_success()
+>>> remove_comitted_on_success = xact_middle(remove_a_reporter)
+>>> remove_comitted_on_success("Alice")
 >>> Reporter.objects.all()
 [<Reporter: Ben Jones>]
+"""
+if not getattr(settings, 'TRANSACTION_POLICY', None)=='safe':
+    __test__['API_TESTS'] += """
+# Note there is a trick with custom sql (in fast_select): Executing it doesn't
+# set the transaction 'dirty', so it may not be committed
+>>> def remove_all_reporters(ignored_request):
+...     cursor = connection.cursor()
+...     sql = 'delete from ' + Reporter._meta.db_table
+...     cursor.execute(sql)
+...
+>>> remove_all_no_commit = xact_middle(remove_all_reporters)
+>>> remove_all_no_commit(None)
+>>> Reporter.objects.all()
+[]
 
-# You can manually manage transactions if you really want to, but you
-# have to remember to commit/rollback
->>> def manually_managed():
-...     r = Reporter(first_name="Carol", last_name="Doe")
-...     r.save()
-...     transaction.commit()
->>> manually_managed = transaction.commit_manually(manually_managed)
->>> manually_managed()
+>>> transaction.rollback()
 >>> Reporter.objects.all()
-[<Reporter: Ben Jones>, <Reporter: Carol Doe>]
+[<Reporter: Ben Jones>]
 
-# If you forget, you'll get bad errors
->>> def manually_managed_mistake():
-...     r = Reporter(first_name="David", last_name="Davidson")
-...     r.save()
-...     # oops, I forgot to commit/rollback!
->>> manually_managed_mistake = transaction.commit_manually(manually_managed_mistake)
->>> manually_managed_mistake()
-Traceback (most recent call last):
-    ...
-TransactionManagementError: Transaction managed block ended with pending COMMIT/ROLLBACK
+# To do it properly, you need to set the transaction dirty
+# when you execute raw SQL
+# set the transaction 'dirty', so it may not be committed
+>>> def remove_all_reporters_dirty(ignored_request):
+...     cursor = connection.cursor()
+...     sql = 'delete from ' + Reporter._meta.db_table
+...     cursor.execute(sql)
+...     transaction.set_dirty()
+...
+>>> remove_all_commit = xact_middle(remove_all_reporters_dirty)
+>>> remove_all_commit(None)
+>>> Reporter.objects.all()
+[]
+
+>>> transaction.rollback()
+>>> Reporter.objects.all()
+[]
 """
+else:
+    __test__['API_TESTS'] += """
+# Under a 'safe' transaction policy, there's no need to set_dirty
+>>> def remove_all_reporters(ignored_request):
+...     cursor = connection.cursor()
+...     sql = 'delete from ' + Reporter._meta.db_table
+...     cursor.execute(sql)
+...
+>>> remove_all_safe = xact_middle(remove_all_reporters)
+
+# See that we have a reporter:
+>>> Reporter.objects.all()
+[<Reporter: Ben Jones>]
+
+>>> remove_all_safe(None)
+
+# Now we don't, and rollback doesn't get it back
+>>> Reporter.objects.all()
+[]
+>>> transaction.rollback()
+>>> Reporter.objects.all()
+[]
+
+"""
