【问题标题】:How to do atomic increment/decrement with Elixir/SQLAlchemy如何使用 Elixir/SQLAlchemy 进行原子递增/递减
【发布时间】:2011-05-09 05:30:05
【问题描述】:

我想增加(或减少)Elixir 实体中的分数字段:

class Posting(Entity):

  score = Field(Integer, PassiveDefault(text('0')))

  def upvote(self):
      self.score = self.score + 1

但是,这不适用于并发调用 upvote。我能想到的最好的就是这个丑陋的混乱(基本上是用 SQLAlchemy 构建一个 SQL UPDATE 语句):

def upvote(self):
    # sqlalchemy atomic increment; is there a cleaner way?
    update = self.table.update().where(self.table.c.id==self.id)
    update = update.values({Posting.score: Posting.score + 1})
    update.execute()

您认为此解决方案有什么问题吗?有没有更清洁的方法来实现同样的目标?

我想避免在这里使用数据库锁。我正在使用 Elixir、SQLAlchemy、Postgres。

更新

这是一个衍生自 vonPetrushev 解决方案的变体:

def upvote(self):
    Posting.query.filter_by(id=self.id).update(
        {Posting.score: Posting.score + 1}
    )

这比我的第一个解决方案要好一些,但仍然需要过滤当前实体。不幸的是,如果实体分布在多个表中,这将不起作用。

【问题讨论】:

    标签: python sqlalchemy python-elixir


    【解决方案1】:

    我会尝试,但我不确定这是否满足您的需求:

    session.query(Posting).\
        .filter(Posting.id==self.id)\
        .update({'score':self.score+1})
    

    你可能想在它之后立即执行 session.commit() 吗?

    编辑:[关于问题的更新]

    如果Posting是从Entity派生出来的,它是类映射到多个表,上面的方案仍然成立,但是Posting.id属性的含义改变了,即不再映射到某个表的列,而是映射到某个表的列不同的组成。这里: http://docs.sqlalchemy.org/en/latest/orm/nonstandard_mappings.html#mapping-a-class-against-multiple-tables 你可以看看如何定义它。我建议它会像:

        j = join(entity_table_1, entity_table_2)
        mapper(Entity, j, properties={
            'id': column_property(entity_table_1.c.id, entity_table_2.c.user_id)
            <... some other properties ...>
        })
    

    【讨论】:

    • 这不是原子操作,分数可能在查询执行之前已经更新。
    猜你喜欢
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-31
    • 2022-06-29
    • 2013-01-27
    相关资源
    最近更新 更多