2015-11-03 73 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