django-4事务
Django 事务(Transaction)是保证数据库操作原子性的关键机制,用于确保一组数据库操作要么全部成功提交,要么在发生错误时全部回滚,从而维持数据的一致性。
事务的 ACID 特性
Django 事务遵循数据库事务的四大特性:
- 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不执行。
- 一致性(Consistency):事务执行前后,数据库从一个有效状态转换到另一个有效状态(如约束、关联关系不变)。
- 隔离性(Isolation):多个事务并发执行时,彼此不会相互干扰(隔离级别决定干扰程度)。
- 持久性(Durability):事务提交后,修改会永久保存到数据库,即使系统崩溃也不会丢失。
事务的使用方式
装饰器 @transaction.atomic(最常用)
将整个函数包装在事务中,函数内所有数据库操作作为一个原子单元。
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 -= quantitybook.save()return order
- 若函数正常执行,事务自动提交。
- 若抛出未捕获的异常(如 ValueError),事务自动回滚。
上下文管理器 with transaction.atomic()
在代码块级别使用事务,更灵活地控制事务范围。
- 适合仅需对部分代码进行事务控制的场景。
- 代码块执行完毕自动提交,异常时自动回滚。
def update_inventory(book_id, new_stock):try:# 事务代码块with transaction.atomic():book = Book.objects.get(id=book_id)book.stock = new_stockbook.save()# 其他操作...print("操作成功,已提交")except Exception as e:print(f"操作失败,已回滚: {e}")
手动控制事务(低级 API)
通过 transaction.begin()
、transaction.commit()
、transaction.rollback()
手动管理事务(不推荐,容易出错)。
def manual_transaction():# 开始事务transaction.set_autocommit(False) # 关闭自动提交try:book = Book.objects.get(id=1)book.stock -= 1book.save()# 手动提交transaction.commit()except:# 出错时回滚transaction.rollback()finally:# 恢复自动提交模式transaction.set_autocommit(True)
事务隔离级别
数据库事务的隔离级别决定了并发事务之间的可见性,Django 支持通过设置隔离级别控制这一行为。
可选隔离级别(因数据库而异)
- READ UNCOMMITTED:最低隔离级别,允许读取未提交的数据(脏读)。
- READ COMMITTED:默认级别(多数数据库),只能读取已提交的数据(避免脏读)。
- REPEATABLE READ:确保同一事务中多次读取的数据一致(避免不可重复读)。
- SERIALIZABLE:最高隔离级别,事务串行执行(避免幻读,性能最低)。
在 Django 中设置隔离级别
全局设置 settings.py)
DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql','NAME': 'mydb','OPTIONS': {'isolation_level': 'read committed', # 或其他级别},}
}
局部设置(针对特定事务):
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):提交保存点(使其成为事务的一部分)。
@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 = Trueuser.save()
并发控制与锁
事务中常需处理并发问题,Django 提供了两种锁机制:
行级锁 select_for_update()
查询时对记录加行锁,阻止其他事务修改该记录,直到当前事务完成。
- 适用于并发修改同一记录的场景(如秒杀、库存扣减)。
- 仅在事务中有效(需配合 atomic)。
@transaction.atomic
def decrease_stock(book_id, quantity):# 加行锁查询(其他事务需等待锁释放)book = Book.objects.select_for_update().get(id=book_id)if book.stock >= quantity:book.stock -= quantitybook.save()else:raise ValueError("库存不足")
表级锁(不推荐)
通过 select_for_update(of=…) 或原生 SQL 实现,会锁定整张表,性能较差,谨慎使用。
注意事项
事务范围不宜过大
避免在事务中包含耗时操作(如网络请求、大量计算),否则会长期占用数据库连接,降低并发性能。
@transaction.atomic
def bad_example():book = Book.objects.get(id=1)send_email() # 耗时的网络操作,不应放在事务中book.stock -= 1book.save()
异常处理
事务仅对数据库操作生效,非数据库操作(如文件写入)不会随事务回滚,需手动处理。
@transaction.atomic
def handle_file_and_db():file_path = "data.txt"try:# 数据库操作book = Book.objects.get(id=1)book.stock += 1book.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 时会临时关闭自动提交,结束后恢复。