2012-11-16 41 views
0

我想執行以下兩個MySQL語句:MySQL的:事務安全插入時行

1) SELECT * FROM table1 WHERE field1=val1 FOR UPDATE; 
2) UPDATE table1 SET field2=val2 WHERE field1=val1; 

重要的是,第二條語句正好改變了由第一條語句(沒有額外的行,沒有一個返回的行減)。因此,我使用auto_commit = false執行事務,並使用select語句的「for update」版本。

「For Update」會鎖定它返回的所有行,因此它們在執行第二條語句時處於原始狀態。但是插入呢?是否有可能另一個線程插入一個帶有field1 = val1 inbetween的新行,然後由第二個語句改變?

還有一個問題:如果第二條語句不改變行本身,但是做了類似下面的事情,它會有所作爲嗎?如果(3)與(1)在同一事務中,那麼確保兩個選擇都返回完全相同的元素嗎?

編輯:

我使用InnoDB和我讀到下一鍵鎖定和差距鎖定一些東西。 據我瞭解,在執行(1)時,InnoDB不僅會鎖定選定的行,還會鎖定訪問的索引。

所以我正確地說,如果我有一個索引在列「field1」上不會發生這個問題?如果沒有索引呢?那有什麼不同呢?

回答

1

我不能完全說話mySQL的情況,但我相當懷疑它。 SELECT FROM ... FOR UPDATE(出現)要做的唯一事情是阻止其他來自modifying the given set of rows的交易。 它不會限制將來的語句 - 如果在運行UPDATE語句之前插入另一行(通過另一個事務),它也會被更新。
不用說,你給出的第三個陳述也將成爲同一個問題的犧牲品。

你試圖在這裏實際做什麼?有可能有另一種方法來實現這一點。例如,如果存在某種'insertedAt'時間戳,則可以將其作爲額外條件添加。

+0

我想收集一些行,計算一些聚合(不是在sql中,但在應用程序代碼中),將聚合結果存儲在某處,然後將讀取的行標記爲「已完成」。確切地說,聚合的行被標記爲「完成」是非常重要的。 – Heinzi

+0

@heinzi - 可能的,但它是一個固有的'硬'問題,定義了一個容錯版本。請創建一個新的問題,其中包含您當前的表格設置,以及問題空間的要求(當然還有目前的情況)。 –

+0

謝謝。我認爲InnoDB提供了一些功能來防止這個普遍問題,但我不確定它們何時應用以及何時不起作用(請參閱上面的編輯)。 – Heinzi