2013-07-17 59 views
2

我已經學會了一點關於數據庫完整性的知識,並且知道如果我「需要多個語句作爲一個單元執行以保持數據處於一致狀態,我應該使用事務」。 Database development mistakes made by application developers(點16,選擇的答案)什麼事務會降低數據的完整性?

Wikipedia使用例如:

  1. 借記$ 100雜貨費用帳戶
  2. 信用$ 100支票帳戶

如果我嘗試存入一筆非 - 存在的帳戶ID,並正確使用約束,將引發異常,我可以捕捉它並回滾。如果發生停電,這兩個變化保證是原子的。


但是,如果我理解正確,自己的交易將不會幫助我在所有的情況下(例如使用PHP和MySQL)

  1. MySQL的:開始交易
  2. MySQL的:選擇數據從表
  3. PHP:計算狀態與所選擇的數據
    • PHP:如果狀態是有效的,插入數據
    • PHP:

這是行不通的,因爲查詢可以同時執行原子不會失敗時提交事務(它的PHP是決定有:否則,請不要將數據

  • 的MySQL一個錯誤,而不是一些SQL約束)。其次,我剛剛測試過,事務是同步提交的,但可以異步啓動。 如果我開始一個事務並添加10秒的延遲,我可以啓動慢速腳本,並在那段時間啓動並提交另一個事務,演示併發事務。兩個實例可以在查看其他修改之前選擇相同的數據。只有修改保證是原子的。


    那麼我該怎麼辦?我想鎖定一張桌子是可行的,但那是一個好習慣嗎?一些條件可以用SQL在單個語句中描述,但更復雜的條件不能。

  • 回答

    1

    這是一個很好的問題。顯示你一直在想這個問題。

    您正在描述的問題存在,因爲數據庫不知道您的數據依賴性。對於數據庫,您的代碼選擇一些數據並寫入一些數據。它不知道你只是根據所選的數據來寫這些數據。一般來說,你需要告訴數據庫你的數據依賴關係。這在每個數據庫中都是不同的。

    你提到了MySQL。 InnoDB支持SELECT ... FOR UPDATE。這將爲資源發出鎖,以便其他查詢無法訪問資源(取決於事務隔離級別)。這將使你的例子中的第二個事務不能夠執行,直到第一個事務提交,如果他們鎖定相同的資源。它鎖定的資源取決於數據庫。

    讓我們來看一個例子。要鎖定行,你會首先創建一個事務,並用類似查詢數據庫:

    select * from tableA where value > 50 for update 
    

    這個選擇將鎖定這些行,以便不兼容鎖將被阻止。然後你可以在PHP中進行處理。一旦你準備好,你可以插入行到另一個表:

    insert into tableB values ('some value') 
    

    在這一點上,在你提交之前,所有這些行,將被鎖定。這些行中沒有一個可用於其他客戶端。因此,在整個交易過程中,除非他們讀取未提交的內容,否則其他客戶端將無法讀取您觸摸的任何行。爲了在你的例子中做到這一點,你只需要確保2中的所有選擇語句都使用select進行更新。

    另一種方法是在更新語句中告訴數據庫。當您發出更新聲明時,您還會指出您認爲數據應該是什麼。如果數據庫確實更新了一些行,那麼您可以確定沒有其他任何更改了您的數據。如果您未更新預期的行數,則可以知道其他人已更改了數據,並且您應該處理該異常。這是樂觀的併發性,你猜可能沒有人會更新你的數據,所以你做了你的改變。之後,您可以檢查是否有人真的做過。

    的查詢是這樣的:

    select value from table where id = '1' 
    

    再後來:

    update table set value = 'new value' where id = '1' and value = 'old value' 
    

    其它數據庫給你這兩個基本概念的其他選項。例如,在樂觀模型上,您可以驗證時間戳(或自動增量)值而不是實際值。

    +0

    嗯,如果我明白這隻對簡單的情況有用,但(這不是問題的要求)。例如,'SELECT ... FOR UPDATE'很重要,但它只適用於使用一行的情況。與'select ... where value = old value'一樣。很高興知道它,但如果我需要選擇大量數據並計算結果以決定是否繼續前進,該怎麼辦?在這些情況下表格鎖定是否可以接受(這似乎是我應該非常小心的事情)? – Raekye

    +0

    @Raekye這兩種技術都可以用於多行,但選擇更新將更容易,因爲它會鎖定所有選定的行。 –

    +0

    我的意思是如果我從多行中選擇數據 - 即使是沒有更新的表,但用於計算條件以查看是否應該插入另一行 – Raekye