2010-11-26 94 views
2

我有一個看起來像這樣的SQLAlchemy的模型對象:如何防止併發插入創建重複項目?

ResultModelBase = declarative_base() 
class Task(ResultModelBase): 
    """Task result/status.""" 

    id = sa.Column(sa.Integer, sa.Sequence("task_id_sequence"), 
        primary_key=True, 
        autoincrement=True) 
    task_id = sa.Column(sa.String(255)) 

在兩個獨立的客戶端進程,該代碼正在運行創造了一個獨特的TASK_ID一個新的實例;必須有隻有一個TASK_ID的實例:

task = session.query(Task).filter(Task.task_id == task_id).first() 
if not task: 
    task = Task(task_id) 
    session.add(task) 
    session.flush() 

我怎麼能改寫這個代碼,以便它以原子創建一個具有指定ID的任務嗎?

回答

0

在代碼塊周圍使用鎖。

# lock here 
task = session.query(Task).filter(Task.task_id == task_id).first() 
if not task: 
    task = Task(task_id) 
    session.add(task) 
    session.flush() 
# unlock here 
+0

我喜歡的東西比這更實用;一,鎖定什麼? – 2010-11-26 21:53:23

2

您的問題是不明確的。數據庫中存在設計缺陷。您無法通過其自動遞增ID來定義行的唯一性。您必須具有將其定義爲唯一的其他字段(例如,task_name + worker),然後通過以下字段創建任務:Task(task_name=smt, worker=smt) - 手動不要放入task_id - 它將自動分配爲下一個表id。使用autoinc主鍵僅用於查找和關係 - 但總是放置由其他表組成的唯一鍵。如果你無法弄清楚哪些字段 - 比你的表未規範化。現在

,用於處理重複插入的問題: 調用Session.flush()#執行以前的工作

session.flush() 
try: 
    t = Task(task_name=smt, worker=smt) 
    session.add() 
    session.flush() 
except sqlalchemy.exc.IntegrityError: 
    # task already exists 
else: 
    # task added to db 
+0

是的,在數據​​庫中添加約束是絕對正確的。 'task_id`應該聲明爲唯一的(並且對於速度也應該有索引):`task_id = sa.Column(sa.String(255),unique = True,index = True)` – 2010-11-27 01:34:16