假设我有一个符合this answer的替换get_or_create
方法,除了我需要将此数据库事务与外部API调用相结合(检查是否存在S3存储桶)。 假设数据库级别存在唯一约束(MySQL InnoDB)。我正在使用eventlet在多个Gunicorn工作进程中运行此代码。
@transaction.commit_on_success
def get_or_create_with_func(obj, func_to_call=None, **kwargs):
try:
result, created = obj.objects.create(**kwargs), True
except IntegrityError:
transaction.commit()
result, created = obj.objects.get(**kwargs), False
func_result = None
if func_to_call is not None and created:
func_result = func_to_call()
return result, created, func_result
交易的成功取决于func_to_call
成功返回(不会引发异常)。如果它引发异常,显然事务将回滚。
我不确定的是,如果2个线程同时使用此函数,create
仍会保存数据库的条目(以便IntegrityError
被引发,{{1}调用返回一个对象),还是必须“等待”直到get
完成?
基本上我正在想象这个场景,上面的函数调用如下:
func_to_call
query_result, created, func_result = get_or_create_with_func(MyModel, external_api_func, model_column=some_value)
。get_or_create_with_func
obj.objects.create
。func_to_call
。IntegrityError
,它不会引发异常。func_to_call
,并按预期获取线程1写入的DB对象。OR
get
并引发异常。func_to_call
,但现在调用IntegrityError
将不会返回任何对象,因为线程1回滚了事务。我的问题是,在第4步,由于表上的唯一约束,get
会失败,或者它会经历,因为线程1还没有真正提交事务(让我们说{{1}很慢)?