2015-11-03 116 views
3

我在使用带有两个工作线程和nginx的uwsgi的MySQL的flask-sqlalchemy中导致并发性问题。烧瓶:使用flask-sqlalchemy的PK违规

我正在使用来自有效负载的密钥。如果联系人带有数据库中存在的密钥,请更新该记录,如果没有,则创建一条新记录。

这里是设置和我认为正在发生的事情。

#project/__init__.py 
app = Flask(__name__) 
db = SQLAlchemy(app) 
from project import views, models 

#project/views.py 
from project import db 

@app.route('/receive', methods = ['POST']) 
def receive(): 

    #Check to see if the contact exists in the database 
    contact = models.Contact.getIssue(contact_payload['id']) 

    if contact is None: 
     #If not in the DB, create a new contact 
     new_contact = models.Contact(contact_payload) 
     db.session.merge(new_contact) 
    else: 
     #If in the DB, create an updated representation of this contact 
     updated_issue = contact.updateContact(contact_payload) 
     db.session.merge(updated_issue) 

    ...Some other stuff... 

    #Commit to DB 
    db.session.commit() 

    #Respond 
    resp = jsonify({'Result' : 'Success'}) 
    resp.status_code = 200 
    return resp 

问题来当我们收到的确切同一时间同一接触两个请求(requestA为12:10:49063和requestB为12:10:49066)。其中一项请求以PK违规行为结束。

我怀疑他们是在不同的工作线程中进来的,每个请求从flask-sqlalchemy获得一个范围会话(sessionA-requestA和sessionB-requestB)。

我怀疑这两个会话在现在同时处于上述代码流中的请求的开始处不包含任何内容。

requestA通过适当的代码流并将new_contact合并到sessionA中。

同时,requestB经过相同的代码路径,其中contact为None(因为sessionA尚未提交)并将new_contact合并到sessionB中。

然后sessionA在sessionB之前提交。当sessionB进行提交时,它会违反PK。

我们可以做其他事情吗?除了抓住PK违规行为并据此做出反应?

回答

0

你有两个选择:

  1. 赶上PK违反和作出相应的反应,就像你已经说了。

  2. 根据你的id锁定你的事务:这更复杂,你需要一些东西来同步你的锁,比如redis。看看python-redis-lock。这只是一个选择,这里的解决方案是为了避免PK的并发。

https://pypi.python.org/pypi/python-redis-lock