2013-03-25 88 views
0

我試圖做到以下幾點:SQL事務,插入,然後更新如果插入成功的是

  • 表A中只有一列由獨特的數字(非連續)
  • 表B有兩列,一個ID(獨特的非連續的整數),並假定一個編號和ID的hit_number(正整數)

,我想:

檢查數量在TA存在BLE A.

  • 如果存在,則什麼也不做,只是讓我知道
  • 如果它不存在,表A插入,增加表B中的hit_number列對應於此身份證,並讓我知道。

它需要在單個事務中完成,如果兩個併發連接要在同一個值中創建,hit_number只應該增加1(所以我需要一些隔離)。

,我想出了一個解決方案(在這個例子中,我使用SQLite和Python),但我不知道它的不夠好:

con = sqlite3.connect(":memory:", isolation_level="EXCLUSIVE") 
con.execute("create table A (num integer primary key);") 
con.execute("create table B (user_id integer primary key, hit_number integer);") 

# ... fill it with something 

def hit(v, id, con): 
    try: 
     with con: 
      con.execute("INSERT INTO A VALUES (?);" + 
         "UPDATE B SET hit_number=hit_number+1 WHERE user_id=(?);", (v, id)) 
    except sqlite3.IntegrityError: 
     return False 
    return True 

這會事務是原子?我在這裏確實需要EXCLUSIVE還是會降低隔離級別給出完全相同的行爲?有沒有更好的辦法?

+0

氣味像非規範化的數據..在任何情況下,1)只使用兩個語句? 2)插入失敗不會阻止更新運行嗎?至於原子性,請參閱http://www.sqlite.org/lockingv3.html – 2013-03-25 21:00:18

+0

如果插入成功並且服務器崩潰並且hit_number永遠不會增加會怎麼樣? – 2013-03-25 21:01:50

+0

查看我發佈的鏈接。要麼使用自動提交(並且僅在數據庫操作完成時提交事務*)或不使用自動提交併且必須手動調用「提交」。 SQLite完全是ACID。無論如何,它似乎仍然是「」「。 – 2013-03-25 21:02:51

回答

4

只執行一個聲明與.execute()方法一次。在一個事務中,從來沒有必要像這樣在一次調用中執行兩個語句;完整性錯誤異常已經提高並中止交易:

try: 
    with con: 
     con.execute("INSERT INTO A VALUES (?);", (v,)) 
     con.execute("UPDATE B SET hit_number=hit_number+1 WHERE user_id=(?);", (id,) 
except sqlite3.IntegrityError: 
    return False 
return True 
+0

所以提供插入成功,當我退出「with con:」塊時,我會得到一個原子提交權。沒有更新A的風險而沒有更新B的權利? – 2013-03-25 21:04:42

+0

@ArthurB .:的確如此。如果沒有異常*,'with'塊提交*。 – 2013-03-25 21:04:54

+0

隔離怎麼樣? 如果我運行兩個像這樣的查詢,並行使用相同的,以前未見過的值v。我可以以v在A中插入的狀態結束,但是沒有(或兩個!)hit_number被更新? 我是否需要*「EXCLUSIVE」隔離級別,或者默認隔離級別是否提供相同的邏輯? – 2013-03-25 21:10:26