• 回滚原理 Since database connections are thread-local, this is thread-safe.


    mysql django

    实践:

     django @transaction.atomic 机制分析
     
     1、数据库清空表Tab
     2、请求django-view
        
        @transaction.atomic(using=settings.TRANSACTION_DEFAULT_USING)
        def post(self, request):
            serializer = self.serializer_class(data=request.data)
            
            
            i = Tab.objects.all()
            print(i[0])
            raise False
        
        
        '''
        控制台输出
        (0.003) SELECT @@SQL_AUTO_IS_NULL; args=None
    (0.003) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None


        '''
        结果可以打印一条db数据
     3、最终数据库表仍为空



    猜想:
     在session中,设置隔离级别为“读提交的”,注意,这里的“提交的”是指其他会话“提交的”,而该会话本身的“未提交”的是在该会话中可以读到的;
     

    @transaction.atomic(using=settings.TRANSACTION_DEFAULT_USING)


    def atomic(using=None, savepoint=True):
    # Bare decorator: @atomic -- although the first argument is called
    # `using`, it's actually the function being decorated.
    if callable(using):
    return Atomic(DEFAULT_DB_ALIAS, savepoint)(using)
    # Decorator: @atomic(...) or context manager: with atomic(...): ...
    else:
    return Atomic(using, savepoint)


    #################################
    # Decorators / context managers #
    #################################

    class Atomic(ContextDecorator):
    """
    Guarantee the atomic execution of a given block.

    An instance can be used either as a decorator or as a context manager.

    When it's used as a decorator, __call__ wraps the execution of the
    decorated function in the instance itself, used as a context manager.

    When it's used as a context manager, __enter__ creates a transaction or a
    savepoint, depending on whether a transaction is already in progress, and
    __exit__ commits the transaction or releases the savepoint on normal exit,
    and rolls back the transaction or to the savepoint on exceptions.

    It's possible to disable the creation of savepoints if the goal is to
    ensure that some code runs within a transaction without creating overhead.

    A stack of savepoints identifiers is maintained as an attribute of the
    connection. None denotes the absence of a savepoint.

    This allows reentrancy even if the same AtomicWrapper is reused. For
    example, it's possible to define `oa = atomic('other')` and use `@oa` or
    `with oa:` multiple times.

    Since database connections are thread-local, this is thread-safe.

    This is a private API.
    """

    def __init__(self, using, savepoint):
    self.using = using
    self.savepoint = savepoint

    def __enter__(self):
    connection = get_connection(self.using)

    if not connection.in_atomic_block:
    # Reset state when entering an outermost atomic block.
    connection.commit_on_exit = True
    connection.needs_rollback = False
    if not connection.get_autocommit():
    # sqlite3 in Python < 3.6 doesn't handle transactions and
    # savepoints properly when autocommit is off.
    # Turning autocommit back on isn't an option; it would trigger
    # a premature commit. Give up if that happens.
    if connection.features.autocommits_when_autocommit_is_off:
    raise TransactionManagementError(
    "Your database backend doesn't behave properly when "
    "autocommit is off. Turn it on before using 'atomic'.")
    # Pretend we're already in an atomic block to bypass the code
    # that disables autocommit to enter a transaction, and make a
    # note to deal with this case in __exit__.
    connection.in_atomic_block = True
    connection.commit_on_exit = False

    if connection.in_atomic_block:
    # We're already in a transaction; create a savepoint, unless we
    # were told not to or we're already waiting for a rollback. The
    # second condition avoids creating useless savepoints and prevents
    # overwriting needs_rollback until the rollback is performed.
    if self.savepoint and not connection.needs_rollback:
    sid = connection.savepoint()
    connection.savepoint_ids.append(sid)
    else:
    connection.savepoint_ids.append(None)
    else:
    connection.set_autocommit(False, force_begin_transaction_with_broken_autocommit=True)
    connection.in_atomic_block = True

    def __exit__(self, exc_type, exc_value, traceback):
    connection = get_connection(self.using)

    if connection.savepoint_ids:
    sid = connection.savepoint_ids.pop()
    else:
    # Prematurely unset this flag to allow using commit or rollback.
    connection.in_atomic_block = False

    try:
    if connection.closed_in_transaction:
    # The database will perform a rollback by itself.
    # Wait until we exit the outermost block.
    pass

    elif exc_type is None and not connection.needs_rollback:
    if connection.in_atomic_block:
    # Release savepoint if there is one
    if sid is not None:
    try:
    connection.savepoint_commit(sid)
    except DatabaseError:
    try:
    connection.savepoint_rollback(sid)
    # The savepoint won't be reused. Release it to
    # minimize overhead for the database server.
    connection.savepoint_commit(sid)
    except Error:
    # If rolling back to a savepoint fails, mark for
    # rollback at a higher level and avoid shadowing
    # the original exception.
    connection.needs_rollback = True
    raise
    else:
    # Commit transaction
    try:
    connection.commit()
    except DatabaseError:
    try:
    connection.rollback()
    except Error:
    # An error during rollback means that something
    # went wrong with the connection. Drop it.
    connection.close()
    raise
    else:
    # This flag will be set to True again if there isn't a savepoint
    # allowing to perform the rollback at this level.
    connection.needs_rollback = False
    if connection.in_atomic_block:
    # Roll back to savepoint if there is one, mark for rollback
    # otherwise.
    if sid is None:
    connection.needs_rollback = True
    else:
    try:
    connection.savepoint_rollback(sid)
    # The savepoint won't be reused. Release it to
    # minimize overhead for the database server.
    connection.savepoint_commit(sid)
    except Error:
    # If rolling back to a savepoint fails, mark for
    # rollback at a higher level and avoid shadowing
    # the original exception.
    connection.needs_rollback = True
    else:
    # Roll back transaction
    try:
    connection.rollback()
    except Error:
    # An error during rollback means that something
    # went wrong with the connection. Drop it.
    connection.close()

    finally:
    # Outermost block exit when autocommit was enabled.
    if not connection.in_atomic_block:
    if connection.closed_in_transaction:
    connection.connection = None
    else:
    connection.set_autocommit(True)
    # Outermost block exit when autocommit was disabled.
    elif not connection.savepoint_ids and not connection.commit_on_exit:
    if connection.closed_in_transaction:
    connection.connection = None
    else:
    connection.in_atomic_block = False


    def atomic(using=None, savepoint=True):
    # Bare decorator: @atomic -- although the first argument is called
    # `using`, it's actually the function being decorated.
    if callable(using):
    return Atomic(DEFAULT_DB_ALIAS, savepoint)(using)
    # Decorator: @atomic(...) or context manager: with atomic(...): ...
    else:
    return Atomic(using, savepoint)










    def atomic(using=None, savepoint=True):
    # Bare decorator: @atomic -- although the first argument is called
    # `using`, it's actually the function being decorated.
    if callable(using):
    return Atomic(DEFAULT_DB_ALIAS, savepoint)(using)
    # Decorator: @atomic(...) or context manager: with atomic(...): ...
    else:
    return Atomic(using, savepoint)








    Database transactions | Django documentation | Django https://docs.djangoproject.com/en/3.0/topics/db/transactions/
    atomic blocks can be nested. In this case, when an inner block completes successfully, its effects can still be rolled back if an exception is raised in the outer block at a later point.










  • 相关阅读:
    Data Structure Binary Tree: Populate Inorder Successor for all nodes
    Data Structure Binary Tree: Connect nodes at same level using constant extra space
    Data Structure Binary Tree: Check if a given Binary Tree is SumTree
    Data Structure Binary Tree: Construct Tree from given Inorder and Preorder traversals
    Data Structure Binary Tree: Inorder Tree Traversal without recursion and without stack!
    Data Structure Binary Tree: Inorder Tree Traversal without Recursion
    Data Structure Binary Tree: How to determine if a binary tree is height-balanced?
    Data Structure Binary Tree: Diameter of a Binary Tree
    Data Structure Binary Tree: Convert an arbitrary Binary Tree to a tree that holds Children Sum Property
    【阿里云产品公测】OpenSearch初体验
  • 原文地址:https://www.cnblogs.com/rsapaper/p/12775895.html
Copyright © 2020-2023  润新知