簡體   English   中英

SQLAlchemy中的條件添加語句

[英]conditional add statement in SQLAlchemy

假設我想將幾個SQL記錄上載到可能尚未填充的表中。 如果在表或要提交到表的記錄中已經存在具有主鍵(“ ID”)的記錄,我想用新記錄替換現有記錄。 我正在使用mssql,SQL Server 2008。

我的第一個猜測是

try:
    session.add(record)
    session.commit
except:
    session.query().\
        filter(Class.ID == record.ID).\
        update(some expression)
    session.commit()       

表達式應該是什么? 有沒有更清潔(更安全!)的方法呢?

通常,除非使用保證原子性的語句,否則您將始終必須考慮可能由於多個參與者嘗試插入或更新(不要忘記刪除)而引起的競爭條件。 即使使用MERGE語句 (即使是單個語句),如果使用不正確也可能具有競爭條件

傳統上,這種“更新”是使用存儲過程或其他SQL或特定於實現的特定功能(例如MERGE語句)執行的。

如果出現完整性錯誤,SQLAlchemy解決方案必須嘗試插入並執行更新,如果不影響任何行,則執行udpate並嘗試插入。 如果兩個操作都失敗(在該行之間可能會刪除或插入一行),則應准備重試:

from sqlalchemy.exc import IntegrityError

while True:  # Infinite loop, use a retry counter  if necessary
    try:
        # begin a save point, prevents the whole transaction failing
        # in case of an integrity error
        with session.begin_nested():
            session.add(record)
            # Flush instead of commit, we need the transaction intact
            session.flush()
            # If the flush is successful, break out of the loop as the insert
            # was performed
            break

    except IntegrityError:
        # Attempt the update. If the session has to reflect the changes
        # performed by the update, change the `synchronize_session` argument.
        if session.query(Class).\
                filter_by(ID=record.ID).\
                update({...},
                       syncronize_session=False):
            # 1 or more rows were affected (hopefully 1)
            break

        # Nothing was updated, perhaps a DELETE in between

    # Both operations have failed, retry

session.commit()

關於

如果在表或要提交到表的記錄中已經存在具有主鍵(“ ID”)的記錄,我想用新記錄替換現有記錄。

如果您可以確定不會對該表進行任何並發更新,則可以將Session.merge用於此類任務:

# Records have primary key set, on which merge can either load existing
# state and merge, or create a new record in session if none was found.
for record in records:
    merged_record = session.merge(record)
    # Note that merged_record is not record

session.commit()

SQLAlchemy合並將首先檢查身份映射中是否存在具有給定主鍵的實例。 如果沒有,並且load作為True傳遞,它將檢查數據庫中的主鍵。 如果給定實例沒有主鍵或找不到實例,則將創建一個新實例。

然后,合並會將給定實例的狀態復制到已定位/創建的實例上。 返回新實例。

否。這樣做有更好的模式。 首先執行查詢以查看記錄是否已經存在,然后進行相應的處理。

使用您的語法,將類似於以下內容:

result = session.query().filter(Class.ID == record.ID).first()

#  If record does not exist in Db, then add record
if result is None:
    try:  
       session.add(record)
       session.commit()
    except:
       db.rollback()
       log.error('Rolling back transaction in query-none block')   

#  If record does exist, then update value of record in Db
else:
   try:
        session.query().\
            filter(Class.ID == record.ID).\
            update(some expression)
        session.commit() 
   except:
       db.rollback()
       log.error('Rolling back transaction')  

將數據庫操作包裝在try / except塊中通常是一個好主意,因此您可以對嘗試的部分進行正確的編寫。 根據您的操作,except塊通常應顯示一條錯誤消息或執行數據庫回滾。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM