django-4事务

Django 事务(Transaction)是保证数据库操作原子性的关键机制,用于确保一组数据库操作要么全部成功提交,要么在发生错误时全部回滚,从而维持数据的一致性。

事务的 ACID 特性

Django 事务遵循数据库事务的四大特性:

  • 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不执行。
  • 一致性(Consistency):事务执行前后,数据库从一个有效状态转换到另一个有效状态(如约束、关联关系不变)。
  • 隔离性(Isolation):多个事务并发执行时,彼此不会相互干扰(隔离级别决定干扰程度)。
  • 持久性(Durability):事务提交后,修改会永久保存到数据库,即使系统崩溃也不会丢失。

事务的使用方式

装饰器 @transaction.atomic(最常用)

将整个函数包装在事务中,函数内所有数据库操作作为一个原子单元。

python 复制代码
from django.db import transaction
from myapp.models import Book, Order

@transaction.atomic
def create_order(book_id, user_id, quantity):
    """创建订单并扣减库存(原子操作)"""
    # 1. 查询书籍(加行锁防止并发问题)
    book = Book.objects.select_for_update().get(id=book_id)
    
    # 2. 检查库存
    if book.stock < quantity:
        raise ValueError("库存不足")  # 触发回滚
    
    # 3. 创建订单
    order = Order.objects.create(
        user_id=user_id,
        book=book,
        quantity=quantity,
        total_price=book.price * quantity
    )
    
    # 4. 扣减库存
    book.stock -= quantity
    book.save()
    
    return order
  • 若函数正常执行,事务自动提交。
  • 若抛出未捕获的异常(如 ValueError),事务自动回滚。

上下文管理器 with transaction.atomic()

在代码块级别使用事务,更灵活地控制事务范围。

  • 适合仅需对部分代码进行事务控制的场景。
  • 代码块执行完毕自动提交,异常时自动回滚。
python 复制代码
def update_inventory(book_id, new_stock):
    try:
        # 事务代码块
        with transaction.atomic():
            book = Book.objects.get(id=book_id)
            book.stock = new_stock
            book.save()
            # 其他操作...
        print("操作成功,已提交")
    except Exception as e:
        print(f"操作失败,已回滚: {e}")

手动控制事务(低级 API)

通过 transaction.begin()transaction.commit()transaction.rollback() 手动管理事务(不推荐,容易出错)。

python 复制代码
def manual_transaction():
    # 开始事务
    transaction.set_autocommit(False)  # 关闭自动提交
    try:
        book = Book.objects.get(id=1)
        book.stock -= 1
        book.save()
        # 手动提交
        transaction.commit()
    except:
        # 出错时回滚
        transaction.rollback()
    finally:
        # 恢复自动提交模式
        transaction.set_autocommit(True)

事务隔离级别

数据库事务的隔离级别决定了并发事务之间的可见性,Django 支持通过设置隔离级别控制这一行为。

可选隔离级别(因数据库而异)

  • READ UNCOMMITTED:最低隔离级别,允许读取未提交的数据(脏读)。
  • READ COMMITTED:默认级别(多数数据库),只能读取已提交的数据(避免脏读)。
  • REPEATABLE READ:确保同一事务中多次读取的数据一致(避免不可重复读)。
  • SERIALIZABLE:最高隔离级别,事务串行执行(避免幻读,性能最低)。

在 Django 中设置隔离级别

全局设置 settings.py

python 复制代码
DATABASES = {
   'default': {
       'ENGINE': 'django.db.backends.postgresql',
       'NAME': 'mydb',
       'OPTIONS': {
           'isolation_level': 'read committed',  # 或其他级别
       },
   }
}

局部设置(针对特定事务):

python 复制代码
from django.db import transaction

@transaction.atomic(isolation_level='serializable')
def critical_operation():
    # 高隔离级别的关键操作
    pass

事务保存点(Savepoint)

在复杂事务中,可设置保存点,允许回滚到事务中的特定位置,而不是整个事务。

  • transaction.savepoint():创建保存点,返回标识。
  • transaction.savepoint_rollback(savepoint):回滚到指定保存点。
  • transaction.savepoint_commit(savepoint):提交保存点(使其成为事务的一部分)。
python 复制代码
@transaction.atomic
def complex_operation():
    # 操作1:创建用户
    user = User.objects.create(username="test")
    
    # 设置保存点
    savepoint = transaction.savepoint()
    
    try:
        # 操作2:创建订单(可能失败)
        order = Order.objects.create(user=user, total=100)
    except Exception as e:
        # 回滚到保存点(仅撤销操作2,保留操作1)
        transaction.savepoint_rollback(savepoint)
        print(f"订单创建失败,已回滚到保存点: {e}")
    else:
        # 提交保存点(操作2生效)
        transaction.savepoint_commit(savepoint)
    
    # 操作3:无论操作2是否成功,都会执行
    user.is_active = True
    user.save()

并发控制与锁

事务中常需处理并发问题,Django 提供了两种锁机制:

行级锁 select_for_update()

查询时对记录加行锁,阻止其他事务修改该记录,直到当前事务完成。

  • 适用于并发修改同一记录的场景(如秒杀、库存扣减)。
  • 仅在事务中有效(需配合 atomic)。
python 复制代码
@transaction.atomic
def decrease_stock(book_id, quantity):
    # 加行锁查询(其他事务需等待锁释放)
    book = Book.objects.select_for_update().get(id=book_id)
    if book.stock >= quantity:
        book.stock -= quantity
        book.save()
    else:
        raise ValueError("库存不足")

表级锁(不推荐)

通过 select_for_update(of=...) 或原生 SQL 实现,会锁定整张表,性能较差,谨慎使用。

注意事项

事务范围不宜过大

避免在事务中包含耗时操作(如网络请求、大量计算),否则会长期占用数据库连接,降低并发性能。

python 复制代码
@transaction.atomic
def bad_example():
    book = Book.objects.get(id=1)
    send_email()  # 耗时的网络操作,不应放在事务中
    book.stock -= 1
    book.save()

异常处理

事务仅对数据库操作生效,非数据库操作(如文件写入)不会随事务回滚,需手动处理。

python 复制代码
@transaction.atomic
def handle_file_and_db():
    file_path = "data.txt"
    try:
        # 数据库操作
        book = Book.objects.get(id=1)
        book.stock += 1
        book.save()
        
        # 文件操作
        with open(file_path, "w") as f:
            f.write("data")
    except:
        # 手动删除已创建的文件
        if os.path.exists(file_path):
            os.remove(file_path)
        raise  # 触发数据库回滚

自动提交模式

Django 默认开启自动提交(autocommit=True),即每个数据库操作单独成事务。使用 atomic 时会临时关闭自动提交,结束后恢复。

相关推荐
笨鸟先飞,勤能补拙1 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
长和信泰光伏储能2 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
浦信仿真大讲堂3 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study3 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境4 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境4 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1234 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy12393102165 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb005 小时前
一个项目带你入门AI应用开发01
python
0566465 小时前
Python康复训练——常用标准库
开发语言·python·学习