peewee,mysql 和自动递增 id

peewee, mysql and auto incrementing id

我在带有 unique=True 字段的 peewee ORM 中有模型。我像这样将数据保存到我的 MySQL 数据库中:

try:
    model.save()
except IntegrityError: # do not save if it's already in db
    pass

但是当 peewee 试图保存已经在数据库中的数据时,MySQL 递增 id 并且 ids 顺序被破坏。如何避免这种行为?

这是我正在尝试保存的模型:

class FeedItem(Model):
    vendor = ForeignKeyField(Vendor, to_field='name')
    url = CharField(unique=True)
    title = CharField()
    pub = DateTimeField()
    rating = IntegerField(default=0)
    img = CharField(default='null')

def construct(self, vendor, url, title):
    self.vendor = vendor
    self.url = url
    self.title = title
    self.pub = datetime.now()
    self.save()

class Meta:
    database = db

我正在保存它:

for article in feedparser.parse(vendor.feed)['items']:
                try:
                    entry = FeedItem()
                    entry.construct(vendor.name, article.link, article.title)
                except IntegrityError:
                    pass

MySQL increments id and ids order is broken. How to avoid this behavior?

你不知道。

数据库生成的标识符不在您的控制范围内。它是由数据库生成的。不能保证所有标识符都必须是连续的且没有间隙,只是它们是唯一的。有许多事情会导致该序列中不存在数字,例如:

  • 一条记录被删除。
  • 尝试插入一条记录,它生成了一个 ID,但在生成该 ID 后插入以某种方式失败。
  • 记录作为未提交事务的一部分被插入。
  • 作为数据库引擎内部优化的一部分,在内存中生成了一组 ID,但在使用这些 ID 之前引擎已关闭。
  • 插入了带有显式 ID 的记录,导致自动递增功能重新调整为新值。

可能还有更多我没有考虑的。但关键是您根本无法控制该值,而是由数据库引擎控制。

如果您想控制该值,请不要使用 autoincrement。但请注意,这会带来一大堆您需要解决的其他问题,而 autoincrement 会为您解决这些问题。或者您必须切换到 GUID 而不是整数,这本身可能会导致您需要考虑的其他注意事项。

我不确定这是否有效,但您可以尝试类似的方法:

try:
    with database.atomic():
        model.save()
except IntegrityError:
    pass  # Model already exists.

通过包装在 atomic() 中,代码将在事务中执行(如果您已经在事务中,则执行保存点)。这可能会导致 ID 序列保持完整。

不过,我同意 David 的回答,即这实际上是一个数据库细节,不应成为您的应用程序逻辑的一部分。如果您需要单调递增的 ID,您应该自己实现。