Mysql 当SQLAlchemy并发更新同一记录时,有什么问题?
我的项目(flask+sqlalchemy)由uWSGI(4名工人)和mysql(使用InnoDB)部署 这些是我的模型: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
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)