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 -= quantity
book.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_stock
book.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 -= 1
book.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 = True
user.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 -= quantity
book.save()
else:
raise ValueError("库存不足")
表级锁(不推荐)
通过 select_for_update(of=…) 或原生 SQL 实现,会锁定整张表,性能较差,谨慎使用。
注意事项
事务范围不宜过大
避免在事务中包含耗时操作(如网络请求、大量计算),否则会长期占用数据库连接,降低并发性能。
@transaction.atomic
def bad_example():
book = Book.objects.get(id=1)
send_email() # 耗时的网络操作,不应放在事务中
book.stock -= 1
book.save()
异常处理
事务仅对数据库操作生效,非数据库操作(如文件写入)不会随事务回滚,需手动处理。
@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 时会临时关闭自动提交,结束后恢复。