【问题标题】:SqlAlchmey add new row to table based on other rows valuesSqlAlchemy 根据其他行值向表中添加新行
【发布时间】:2020-02-09 14:53:10
【问题描述】:

在下面的代码中,如果表中有一行:

1-partnerId 列的值和我预期的一样

2- 并且这一行的状态现在是open

插入后我想将过滤行的状态更改为booked

        partner = db.session.query(TransferRequest).filter(TransferRequest.id == partner_id).one()
        if partner.status == RequestStatus.open.value:
            request = TransferRequest()
            #set values

            db.session.add(request)
            db.session.commit()

            db.session.query(TransferRequest). \
                filter(TransferRequest.id == partner_id). \
                update({"status": RequestStatus.booked.value,
                        "partnerId": request.id})
            db.session.commit()

            return "success"
        else:
            return "failure"

这里的问题是,当我查询具有特定 id 的项目并检查其状态时,在达到if 条件后,其他人可能会将行的状态从open 更改为booked。在这种情况下,我不能插入行,并且不能在插入后执行update 命令。

我正在寻找一种可以在事务中执行所有这 3 个查询的方法,以便所有数据情况从第一条语句锁定到结束语句。 (或者当然可以解决问题的任何其他解决方案)

【问题讨论】:

    标签: python sql flask sqlalchemy flask-sqlalchemy


    【解决方案1】:

    我认为您代码中的主要问题是两次使用 commit()。它将所有内容提交到数据库(作为事务),然后释放底层事务锁。第二件事是,我还应该将 with_for_update() 添加到您的选择查询中,以锁定特定行。以一次性提交结束,以保留您的更改并释放锁定。一个例子可能是:

        session = sessionmaker(bind=engine, autocommit=False)
    
        partner = session.query(TransferRequest).with_for_update().filter(TransferRequest.id == partner_id).one()
        if partner.status == RequestStatus.open.value:
            request = TransferRequest()
            #set values
    
            session.add(request)
            session.flush()
    
            session.query(TransferRequest). \
                filter(TransferRequest.id == partner_id). \
                update({"status": RequestStatus.booked.value,
                        "partnerId": request.id})
            session.commit()
    
            return "success"
        else:
            return "failure"
    

    【讨论】:

    • 是否只提交一次会导致我对“TransferRequest”的第一个查询锁定该行并且不允许其他人更改过滤行的状态?因为我担心在过滤之后,在设置值的代码之间,将它们添加到表中并更新过滤的行另一个请求会更快执行并在我预订之前预订该行。我想避免这种情况。
    • 对于这个确切的行为,我添加了 with_for_update(),这应该是您需要在选择期间对行进行锁定。有关此方法的更多信息:stackoverflow.com/questions/40700309/…
    • 问题是如果我删除第一个提交,用于更新过滤行的request.id 没有任何值,因为id 是和autoincrement 字段
    • 你可能会使用 flush() 而不是你的第一个 commit()
    猜你喜欢
    • 2020-08-03
    • 1970-01-01
    • 2021-07-27
    • 1970-01-01
    • 1970-01-01
    • 2020-02-12
    • 2014-02-28
    • 1970-01-01
    • 2022-12-17
    相关资源
    最近更新 更多