我的项目(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
但有时候我没有得到预期的结果,例如:
select * from trans_details order by `timestamp` desc;
|from_card |to_card |amount |from_card_balance |to_card_balance |timestamp
A C 100 1000(This Should be 950) xxx 1413257244.5339300(2014-10-14 11:27:24)
A B 50 1050 150 1413257244.4818400(2014-10-14 11:27:24)
B A 100 100 1100 xxx
我该如何解决?
答案 0 :(得分:1)
我修好了。是我的问题,我的代码如下:
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)