捕获IntegrityError与创建对象前过滤:哪种方案更优?
问题:两种数据库对象创建方案哪种更优?
我有一项开发任务,需通过函数创建数据库对象,该函数接收第三方客户端请求返回的多个JSON对象。我遍历这些JSON对象,逐一调用_create_db_object方法创建对象。
示例模型:
class MyObject(models.Model): some_unique_field = models.CharField(unique=True) ... ...
当前创建对象的函数:
def _create_db_object(dict_: dict[str, str]) -> None: try: return MyObject.objects.create(...) except IntegrityError as e: continue
我想知道:改用以下先过滤再创建的函数是否更好?
def _create_db_object(dict_: dict[str, str]) -> None: if MyObject.objects.filter(some_unique_field=dict_["unique_field"]): continue return MyObject.objects.create(...)
哪种方案更优?原因是什么?
分析与结论
推荐使用第一种捕获IntegrityError的方案,原因如下:
避免竞态条件:第二种方案的「查询-创建」是两步分离操作,高并发场景下可能出现多个请求同时通过查询(此时目标记录还不存在),随后同时执行创建操作,最终触发数据库唯一约束报错。而第一种方案直接依赖数据库的唯一约束做最终校验,创建操作是原子性的,不会出现这类问题。
性能更高效:第二种方案每次创建前都要多执行一次查询;第一种方案只有在遇到重复数据时才会触发异常捕获,多数数据不重复的场景下,只需要一次创建操作,整体效率更高。
代码更简洁可靠:第一种方案不需要额外编写查询逻辑,直接利用数据库本身的约束保证唯一性,代码更简洁,也符合依赖底层约束保障数据一致性的最佳实践。
只有在低并发且重复数据占比极高的极端场景下,第二种方案能减少异常抛出次数,但这种场景非常少见。绝大多数业务场景中,捕获IntegrityError的方案是更稳妥、高效的选择。
内容的提问来源于stack exchange,提问作者Burakhan Aksoy
相关产品推荐
相关产品推荐

