Mysql 当SQLAlchemy并发更新同一记录时,有什么问题?

Mysql 当SQLAlchemy并发更新同一记录时,有什么问题?,mysql,flask,sqlalchemy,Mysql,Flask,Sqlalchemy,我的项目(flask+sqlalchemy)由uWSGI(4名工人)和mysql(使用InnoDB)部署 这些是我的模型: class Cards(db.Model): id =db.Column(db.Integer, primary_key = True) no =db.Column(db.String(11),index=True, unique = True,nullable=False) balance

我的项目(flask+sqlalchemy)由uWSGI(4名工人)和mysql(使用InnoDB)部署

这些是我的模型:

class Cards(db.Model):
    id             =db.Column(db.Integer, primary_key = True)
    no             =db.Column(db.String(11),index=True, unique = True,nullable=False)
    balance        =db.Column(db.Numeric(12,2),nullable=False,default=0)


class trans_details(db.Model):
    id             =db.Column(db.Integer, primary_key = True)
    from_card_id   =db.Column(db.Integer, db.ForeignKey('cards.id'),nullable=False)
    to_card_id     =db.Column(db.Integer, db.ForeignKey('cards.id'),nullable=False)
    amount         =db.Column(db.Numeric(12,2),nullable=False)

    from_card_balance=db.Column(db.Numeric(12,2),nullable=False)
    to_card_balance  =db.Column(db.Numeric(12,2),nullable=False

    timestamp      =db.Column(db.Numeric(17,7),default=time.time,nullable=False)#时间戳

    from_card      =db.relationship('Cards',foreign_keys=[from_card_id],
                    backref=db.backref('out_details',lazy='dynamic'))
    to_card        =db.relationship('Cards',foreign_keys=[to_card_id],
                    backref=db.backref('in_details',lazy='dynamic'))
我的代码是这样的:

@contextmanager
def trans():
    try:
        yield
        db.session.commit()
    except:
        db.session.rollback()

def transfer(from_card,to_card,amount):
    with trans():
        from_card.balance=Cards.balance-amount
        to_card.balance=Cards.balance+amount

        db.session.add(from_card)
        db.session.add(to_card)
        db.session.flush()

        if from_card.balance<0:
            raise Exception('xxx')

        details=trans_details(from_card=from_card,
                          to_card=to_card,
                          amount=amount,
                          from_card_balance=from_card.balance,
                          to_card_balance=to_card.balance)
        db.session.add(details)
        db.session.flush()

def batch_transfer(rule):
    with trans():
        #parse the rule and call transfer function time after time

如何修复它?

我修复了它。是我的问题,我的代码如下:

from_card=Cards.query.with_for_update().filter(xxx)
to_card=Cards.query.with_for_update().filter(xxx)
#call a function here,but in the function have a commit operation so..
transfer(from_card,to_card,amount)

我知道这对你来说可能已经太晚了,但对这个解决方案只是一个评论,因为其他人可能会偶然发现它:这可能会导致僵局。假设两个事务同时执行。一个从帐户A到B,另一个从帐户B到A。第一个交易现在可能会锁定帐户A,第二个交易可能会锁定帐户B。要避免这种情况,您只需使用一个查询返回两张卡,而不是两个单独的查询。即使这样,我也不确定MySQL是否能保证免于死锁。
from_card=Cards.query.with_for_update().filter(xxx)
to_card=Cards.query.with_for_update().filter(xxx)
#call a function here,but in the function have a commit operation so..
transfer(from_card,to_card,amount)