SQLite+SQLAlchemy中ON CONFLICT DO NOTHING后获取插入对象ID问题
问题解答
1. 错误为何出现在创建MarketItemPriceHistory而非MarketItem时?
因为你给所有INSERT语句加了ON CONFLICT DO NOTHING,第二次运行时,MarketItem的插入操作因冲突被直接跳过,不会抛出错误。但代码逻辑仍基于「MarketItem已成功插入」的前提去创建关联的MarketItemPriceHistory,此时PriceHistory依赖的外键实际不存在,才触发了外键约束错误。而MarketItem本身的插入因DO NOTHING的存在,不会报错。
2. 错误参数中marketitemid为0的原因是什么?
SQLAlchemy中,整数类型的主键字段在模型对象未被数据库持久化(即未成功插入)时,默认值为0。第二次运行时,MarketItem的插入被跳过,对象的主键ID没有从数据库获取到自增的实际值,仍保持初始的0,当用这个对象关联创建MarketItemPriceHistory时,就会把0作为外键值传入,而数据库中不存在marketitemid=0的记录,触发约束错误。
3. 如何无需预查数据存在性,获取MarketItem实际ID来创建关联的MarketItemPriceHistory?
可以通过修改ON CONFLICT逻辑,让插入操作无论是否冲突都返回对应记录的ID:
- 对于PostgreSQL等支持
RETURNING和ON CONFLICT DO UPDATE的数据库,将ON CONFLICT DO NOTHING改为ON CONFLICT (唯一约束字段) DO UPDATE SET id = id(无实际更新操作),同时加上RETURNING id。这样不管是新插入还是冲突跳过,都会返回该MarketItem的实际ID。 - 在SQLAlchemy中执行插入后,直接提取返回的ID值,用这个ID创建MarketItemPriceHistory。如果用ORM操作,可使用
session.execute配合插入语句,拿到返回结果后提取ID再关联创建PriceHistory对象。 - 也可以使用SQLAlchemy的
merge()方法,它会自动判断对象是否存在:存在则返回数据库中的现有对象(带实际ID),不存在则插入新对象。merge()内部会自动处理查询逻辑,无需开发者手动写预查代码。
内容的提问来源于stack exchange,提问作者qwerty_url
相关产品推荐
相关产品推荐

