本節書摘來自異步社群出版社《sql入門經典(第5版)》一書中的第6章,第6.2節,作者:【美】ryan stephens , ron plew , arie d.jones,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。
sql入門經典(第5版)
事務控制是對關系型資料庫管理系統(rdbms)裡可能發生的各種事務的管理能力。在談及事務時,我們是指前一章所介紹的insert、update和delete指令。
by注意:
事務的啟動或執行在各個實作中是不同的,詳細情況請檢視具體實作的文檔。
當一個事務被執行并成功完成時,雖然從輸出結果來看目标表已經被修改了,但實際上目标表并不是立即被修改。當事務成功完成時,利用事務控制指令最終認可這個事務,可以把事務所做的修改儲存到資料庫,也可以撤銷事務所做的修改。
控制事務的指令有3個:
commit;
rollback;
savepoint。
下面的小節将詳細介紹這3個指令。
by注意:什麼時候可以使用事務
事務控制指令隻與dml指令insert、update和delete配合使用,比如我們不會在建立表之後使用commit語句,因為當表被建立之後,它會自動被送出給資料庫。也不能使用rollback語句來恢複被撤銷的表。此外,還有其他類似的語句,也是不能被撤銷的,例如truncate語句。是以,在運作新的指令前,最好先确認一下使用者所使用的rdbms在事務方面的相關規定。
當事務完成之後,事務資訊被儲存在資料庫裡的指定區域或臨時回退區域。所有的修改都被儲存到這個臨時回退區域,直到事務控制指令出現。當事務控制指令出現時,所做的修改要麼被儲存到資料庫,要麼被放棄,然後臨時回退區域被清空。圖6.1展示了修改操作如何應用到關系型資料庫。
commit指令用于把事務所做的修改儲存到資料庫,它把上一個commit或rollback指令之後的全部事務都儲存到資料庫。
這個指令的文法是:
關鍵字commit是文法中唯一不可缺少的部分,其後是用于終止語句的字元或指令,具體内容取決于不同的實作。關鍵字work是個選項,其唯一作用是讓指令對使用者更加友好。
在下面這個範例裡,我們首先從查詢表product_tmp裡的全部資料開始:
接下來,删除表裡所有價格低于$14.00的産品。
使用一個commit語句把修改儲存到資料庫,完成這個事務。
對于資料庫的大規模資料加載或撤銷來說,應該多使用commit語句;然而,過多的commit語句會讓工作需要大量額外時間才能完成。記住,全部修改都首先被送到臨時回退區域,如果這個臨時回退區域沒有空間了,不能儲存對資料庫所做的修改,資料庫很可能會挂起,禁止進一步的事務操作。
實際上,在送出了一條update、insert或delete語句之後,大部分rdbms都是使用事務來進行背景處理的,一旦操作被取消或報錯,所做的操作就可以被撤銷。是以,在送出了一個事務之後,會有一系列操作來確定事務正常運作。在現實生活中,使用者可能會在atm上送出一個銀行事務以便從自己的賬戶中取出現金。這時,就需要完成取錢和更新賬戶餘額兩項事務。很顯然,我們希望這兩項事務能夠同時完成,或者全部失敗。否則,系統資料的完整性就會受到影響。是以,在這個執行個體中,我們會将兩項操作合并為一個事務,來確定對操作結果的控制。
..by.tif注意:不同的實作對commit指令的送出有所不同
在某些實作裡,事務不是通過使用commit指令送出的,而是由退出資料庫的操作引發送出。但是在其他實作裡,比如mysql,在執行set transaction指令之後,在資料庫收到commit或rollback之前,自動送出功能是不會恢複的。此外,在microsoft sql server中,除非事務正在運作,否則語句會被自動送出。是以,使用者務必要了解所使用的rdbms在事務處理和指令送出方面的相關規定。
rollback指令用于撤銷還沒有被儲存到資料庫的指令,它隻能用于撤銷上一個commit或rollback指令之後的事務。
rollback的文法如下所示:
與commit指令一樣的是,關鍵字work隻是個選項。
在下面的範例裡,首先選擇表products_tmp裡的全部記錄,這是前一次删除14條記錄之後所剩的資料。
接下來更新表,把辨別為11235的産品價格修改為$39.99:
現在對表進行一個簡單的查詢,可以發現修改似乎已經生效了:
現在,執行rollback指令來撤銷剛剛所做的修改:
最後,驗證所做的修改并沒有被送出到資料庫:
儲存點是事務過程中的一個邏輯點,我們可以把事務回退到這個點,而不必回退整個事務。
savepoint指令的文法如下:
這個指令就是在事務語句之間建立一個儲存點。rollback指令可以撤銷一組事務操作,而儲存點可以将大量事務操作劃分為較小的、更易于管理的組。
microsoft sql server的文法稍有不同。在sql server中,使用的是save transac- tion,而不是savepoint,範例如下:
除此之外,sql server與其他資料庫實作完全相同。
回退到儲存點的指令文法如下:
在下面的範例裡,我們要從表porducts_tmp表裡删除剩餘的資料,在進行每次删除之前都使用savepoint指令,這樣就可以在任何時候利用rollback指令回退到任意一個儲存點,進而把适當的資料恢複到原始狀态:
在相應的事務操作組裡,儲存點的名稱必須是唯一的,但其名稱可以與表或其他對象的名稱相同,詳細的命名規範請見具體實作的說明文檔。儲存點名稱的設定屬于個人喜好,它隻被資料庫開發人員用來管理事務操作組。
在三次删除操作完成之後,假設我們又改變了主意,決定回退到名為sp2的儲存點。由于sp2是在第一次删除操作之後建立的,是以這樣做會撤銷最後兩次删除操作:
現在檢視表裡的内容,可以發現隻發生了第一次删除操作:
記住,rollback指令本身會回退到上一個commit或rollback語句。由于我們還沒有執行commit指令,是以這時執行rollback指令會撤銷全部删除指令,如下所示:
這個指令用于删除建立的儲存點。在某個儲存點被釋放之後,就不能再利用rollback指令來撤銷這個儲存點之後的事務操作了。利用這個指令可以避免意外地回退到某個不再需要的儲存點。
microsoft sql server不支援release savepoint指令;在事務完成以後,所有的儲存點會被自動删除。這個過程不必使用commit 或者 rollback指令。使用者在自己的環境中建立事務時,需要牢記這一點。
這個指令用于初始化資料庫事務,可以指定事務的特性。舉例來說,我們可以指定事務是隻讀的或是可以讀寫的,如下所示:
read write用于對資料庫進行查詢和操作資料的事務,read only用于隻進行查詢的事務。read only很适合生成報告,而且能夠提高事務完成的速度。如果事務是read write類型的,資料庫必須對資料庫對象進行加鎖,進而在多個事務同時發生時保持資料完整性。如果事務是read only,資料庫就不會建立鎖定,這樣就會提高事務的性能。
事務還可以設定其他特性,但超出了本書的讨論範圍。mysql通過對事務實作不同級别的隔離來實作類似功能,但文法略有不同。詳細情況請參考具體實作的幫助文檔。