Django ORM事务隔离级别与分布式锁的配合
Django ORM提供了transaction.atomic()上下文管理器进行事务控制。请介绍Django ORM中如何设置事务隔离级别(transaction.set_isolation_level()/数据库配置)、select_for_update()行级锁的使用,以及在高并发场景下如何配合Redis分布式锁防止超卖/重复提交。
回答
苦行僧
Django事务基础
from django.db import transaction
# 原子事务
with transaction.atomic():
user = User.objects.select_for_update().get(pk=1)
user.balance -= 100
user.save()
Order.objects.create(user=user, amount=100)
# 自动commit或rollback
# 手动控制
try:
with transaction.atomic():
# 数据库操作
raise SomeError()
# 到这里会自动rollback
except:
pass # 事务已回滚
事务隔离级别设置
# 方式1:数据库配置(settings.py)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'OPTIONS': {
'isolation_level': 'repeatable_read',
},
}
}
# 方式2:session级别(Django 3.0+)
from django.db import connection
with connection.cursor() as cursor:
cursor.execute('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE')
select_for_update() — 行级锁
# 悲观锁:锁定行直到事务结束
with transaction.atomic():
# 添加nowait=True防止等待锁(直接报错)
# 添加skip_locked=True跳过已被锁的行
user = User.objects.select_for_update(nowait=True).get(pk=1)
if user.balance >= 100:
user.balance -= 100
user.save()
分布式锁+事务(防超卖)
import redis
from django.db import transaction
redis_client = redis.Redis()
lock_key = f'product_lock:{product_id}'
# 获取Redis分布式锁
with redis_client.lock(lock_key, timeout=10):
with transaction.atomic():
product = Product.objects.select_for_update().get(pk=product_id)
if product.stock <= 0:
raise Exception('库存不足')
product.stock -= 1
product.save()
Order.objects.create(
user=request.user,
product=product,
quantity=1
)
最佳实践:
- 单数据库:
select_for_update()+transaction.atomic() - 跨数据库/微服务:Redis分布式锁 + 重试机制
- 高并发秒杀:Redis原子操作预扣 + 异步订单创建