MySQL心得10-1--事務
1. 在MySQL環境中,事務由作為一個單獨單元的一個或多個SQL語句組成。這個單元中的每個SQL語句是互相依賴的,而且單元作為一個整體是不可分割的。如果單元中的一個語句不能完成,整個單元就會回滾(撤銷),所有影響到的數據將返回到事務開始以前的狀態。因而,只有事務中的所有語句都成功地執行才能說這個事務被成功地執行。
www.2cto.com
2.並不是所有的存儲引擎都支持事務,如InnoDB和BDB支持,但MyISAM和MEMORY不支持。
通過InnoDB和BDB表類型,MySQL 事務系統能夠完全滿足事務安全的ACID測試。舊的表類型,如MyISAM類型,不支持事務。因此,這種系統中的事務只能通過直接的表鎖定實現。
術語“ACID”是一個簡稱,每個事務的處理必須滿足ACID原則,即原子性:A(atom)、一致性:C(consistent)、隔離性:I(independence)、持久性:D(durability)。
(1)原子性
原子性意味著每個事務都必須被認為是一個不可分割的單元。假設一個事務由兩個或者多個任務組成,其中的語句必須同時成功才能認為事務是成功的。如果事務失敗,系統將會返回到事務以前的狀態。
在添加雇員這個例子中,原子性指如果沒有創建雇員相應的工資表和部門記錄,就不可能向雇員數據庫添加雇員。 www.2cto.com
原子的執行是一個或者全部發生或者什麼也沒有發生的命題。在一個原子操作中,如果事務中的任何一個語句失敗,前面執行的語句都將返回,以保證數據的整體性沒有受到影響。這在一些關鍵系統中尤其重要,現實世界的應用程序(如金融系統:轉賬)執行數據輸入或更新,必須保證不出現數據丟失或數據錯誤,以保證數據安全性。
(2)一致性
不管事務是完全成功完成還是中途失敗,當事務使系統處於一致的狀態時存在一致性。參照前面的例子,一致性是指如果從系統中刪除了一個雇員,則所有和該雇員相關的數據,包括工資數據和組的成員資格也要被刪除。
在MySQL中,一致性主要由MySQL的日志機制處理,它記錄了數據庫的所有變化,為事務恢復提供了跟蹤記錄。如果系統在事務處理中間發生錯誤,MySQL恢復過程將使用這些日志來發現事務是否已經完全成功地執行,是否需要返回。因而一致性屬性保證了數據庫從不返回一個未處理完的事務。
(3)隔離性
隔離性是指每個事務在它自己的空間發生,和其他發生在系統中的事務隔離,而且事務的結果只有在它完全被執行時才能看到。即使在這樣的一個系統中同時發生了多個事務,隔離性原則保證某個特定事務在完全完成之前,其結果是看不見的。
當系統支持多個同時存在的用戶和連接時(如MySQL),這就尤其重要。如果系統不遵循這個基本規則,就可能導致大量數據的破壞,如每個事務的各自空間的完整性很快地被其他沖突事務所侵犯。
獲得絕對隔離性的唯一方法是保證在任意時刻只能有一個用戶訪問數據庫。當處理像MySQL這樣多用戶的RDBMS時,這不是一個實際的解決方法。但是,大多數事務系統使用頁級鎖定或行級鎖定隔離不同事務之間的變化,這是要以降低性能為代價的。例如,MySQL的BDB表處理程序使用頁級鎖定來保證處理多個同時發生的事務的安全,InnoDB表處理程序使用更好的行級鎖定。
(4)持久性
持久性是指即使系統崩潰,一個提交的事務仍然存在。當一個事務完成,數據庫的日志已經被更新時,持久性就開始發生作用。大多數RDBMS產品通過保存所有行為的日志來保證數據的持久性,這些行為是指在數據庫中以任何方法更改數據。數據庫日志記錄了所有對於表的更新、查詢、報表等。
如果系統崩潰或者數據存儲介質被破壞,通過使用日志,系統能夠恢復在重啟前進行的最後一次成功的更新,反映了在崩潰時處於過程的事務的變化。
MySQL通過保存一條記錄事務過程中系統變化的二進制事務日志文件來實現持久性。如果遇到硬件破壞或者突然的系統關機,在系統重啟時,通過使用最後的備份和日志就可以很容易地恢復丟失的數據。
默認情況下,InnDB表是100%持久的(所有在崩潰前系統所進行的事務在恢復過程中都可以可靠地恢復)。MyISAM表提供部分持久性,所有在最後一個FLUSH TABLES命令前進行的變化都能保證被存盤。
www.2cto.com
3.事務是由一組SQL語句構成的,它由一個用戶輸入,並以修改成持久的或者滾到原來狀態而終結。
在MySQL中,當一個會話開始時,系統變量AUTOCOMMIT值為1,即自動提交功能是打開的,當用戶每執行一條SQL語句後,該語句對數據庫的修改就立即被提交成為持久性修改保存到磁盤上,一個事務也就結束了。因此,用戶必須關閉自動提交,事務才能由多條SQL語句組成,使用語句:SET@@AUTOCOMMIT=0;執行此語句後,必須明確地指示每個事務的終止,事務中的SQL語句對數據庫所做的修改才能成為持久化修改。例如,執行如下語句:
DELETE FROM XS WHERE 學號='081101';
SELECT * FROM XS;
從執行結果中發現,表中已經刪去了一行。但是,這個修改並沒有持久化,因為自動提交已經關閉了。用戶可以通過ROLLBACK撤銷這一修改,或者使用COMMIT語句持久化這一修改。
4. 具體介紹如何處理一個事務。
1). 開始事務
當一個應用程序的第一條SQL語句或者在COMMIT或ROLLBACK語句(後面介紹)後的第一條SQL執行後,一個新的事務也就開始了。另外還可以使用一條start transaction語句來顯示地啟動一個事務。 語法格式: START TRANSACTION | BEGINWORK
一條BEGIN WORK語句可以用來替代STARTTRANSACTION語句,但是START TRANSACTION更常用些。
2). 結束事務
COMMIT語句是提交語句,它使得自從事務開始以來所執行的所有數據修改成為數據庫的永久部分,也標志一個事務的結束,其語法格式為: COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
說明:可選的and chain子句會在當前事務結束時,立刻啟動一個新事務,並且新事務與剛結束的事務有相同的隔離等級。Release子句在終止了當前事務後,會讓服務器斷開與當前客戶端的連接。包含NO關鍵詞可以抑制CHAIN或RELEASE完成。
注意:MySQL使用的是平面事務模型,因此嵌套的事務是不允許的。在第一個事務裡使用START TRANSACTION命令後,當第二個事務開始時,自動地提交第一個事務。同樣,下面的這些MySQL語句運行時都會隱式地執行一個COMMIT命令:
● DROP DATABASE / DROP TABLE
● CREATE INDEX / DROP INDEX
● ALTER TABLE / RENAME TABLE
● LOCK TABLES / UNLOCK TABLES
● SET AUTOCOMMIT=1
3). 撤消事務
Rollback語句是撤銷語句,它撤銷事務所做的修改,並結束當前這個事務。 語法格式:
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
在前面的舉例中,若在最後加上以下這條語句: ROLLBACKWORK;
執行完這條語句後,前面的刪除動作將被撤銷,可以使用SELECT語句查看該行數據是否還原。
4). 回滾事務
www.2cto.com
除了撤銷整個事務,用戶還可以使用ROLLBACK TO語句使事務回滾到某個點,在這之前需要使用savepoint語句來設置一個保存點。
SAVEPOINT語法格式為: SAVEPOINTidentifier(保存點的名稱)。
ROLLBACK TO SAVEPOINT語句會向已命名的保存點回滾一個事務。如果在保存點被設置後,當前事務對數據進行了更改,則這些更改會在回滾中被撤銷。語法格式為:
ROLLBACK [WORK] TO SAVEPOINT identifier
當事務回滾到某個保存點後,在該保存點之後設置的保存點將被刪除。RELEASESAVEPOINT語句會從當前事務的一組保存點中刪除已命名的保存點。不出現提交或回滾。如果保存點不存在,會出現錯誤。語法格式為: RELEASE SAVEPOINT identifier
5. 舉例說明:下面幾個語句說明了有關事務的處理過程:
1. START TRANSACTION
2. UPDATE …
3. DELETE…
4. SAVEPOINT S1;
5. DELETE…
6. ROLLBACK WORK TO SAVEPOINT S1;
7. INSERT…
8. COMMIT WORK;
說明:在以上語句中,第1行語句開始了一個事務;第2、3行語句對數據進行了修改,但沒有提交;第4行設置了一個保存點;第5行刪除了數據,但沒有提交;第6行將事務回滾到保存點S1,這時第5行所做修改被撤銷了;第7行修改了數據;第8行結束了這個事務,這時第2、3、7行對數據庫做的修改被持久化。
6.每一個事務都有一個所謂的隔離級,它定義了用戶彼此之間隔離和交互的程度。前面曾提到,事務型RDBMS的一個最重要的屬性就是它可以“隔離”在服務器上正在處理的不同的會話。在單用戶的環境中,這個屬性無關緊要:因為在任意時刻只有一個會話處於活動 狀態。但是在多用戶環境中,許多RDBMS會話在任一給定時刻都是活動的。在這種情況下,RDBMS能夠隔離事務是很重要的,這樣它們不互相影響,同時保證數據庫性能不受到影響。
www.2cto.com
為了了解隔離的重要性,有必要花些時間來考慮如果不強加隔離會發生什麼。如果沒有事務的隔離性,不同的SELECT語句將會在同一個事務的環境中檢索到不同的結果,因為在這期間,基本上數據已經被其他事務所修改。這將導致不一致性,同時很難相信結果集,從而不能利用查詢結果作為計算的基礎。因而隔離性強制對事務進行某種程度的隔離,保證應用程序在事務中看到一致的數據。
基於ANSI/ISO SQL規范,MySQL提供了下面4種隔離級:序列化(serialization)、可重復讀(repeatable read)、提交讀(read committed)、未提交讀(read uncommitted)。
7. 只有支持事務的存儲引擎才可以定義一個隔離級。定義隔離級可以使用SET TRANSACTION語句。語法格式:
SET [GLOBAL | SESSION] TRANSACTION Isolationlevel
SERIALIZABLE
| REPEATABLE READ
| READ COMMITTED
| READ UNCOMMITTED
說明:
如果指定GLOBAL,那麼定義的隔離級將適用於所有的SQL用戶;如果指定SESSION,則隔離級只適用於當前運行的會話和連接。MySQL默認為REPEATABLE READ隔離級。
(1)序列化
如果隔離級為序列化,用戶之間通過一個接一個順序地執行當前的事務提供了事務之間最大限度的隔離。
(2)可重復讀
在這一級上,事務不會被看成是一個序列。不過,當前在執行事務的變化仍然不能看到,也就是說,如果用戶在同一個事務中執行同條SELECT語句數次,結果總是相同的。
(3)提交讀
READ COMMITTED隔離級的安全性比REPEATABLE READ隔離級的安全性要差。不僅處於這一級的事務可以看到其他事務添加的新記錄,而且其他事務對現存記錄做出的修改一旦被提交,也可以看到。也就是說,這意味著在事務處理期間,如果其他事務修改了相應的表,那麼同一個事務的多個SELECT語句可能返回不同的結果。
(4)未提交讀
www.2cto.com
提供了事務之間最小限度的隔離。除了容易產生虛幻的讀操作和不能重復的讀操作外,處於這個隔離級的事務可以讀到其他事務還沒有提交的數據,如果這個事務使用其他事務不提交的變化作為計算的基礎,然後那些未提交的變化被它們的父事務撤銷,這就導致了大量的數據變化。
默認情況下,這個系統變量的值是基於每個會話設置的,但是可以通過向SET命令行添加GLOBAL關鍵字修改該全局系統變量的值。
當用戶從無保護的READUNCOMMITTED隔離級轉移到更安全的SERIALIZABLE級時,RDBMS的性能也要受到影響。原因很簡單:用戶要求系統提供越強的數據完整性,它就越需要做更多的工作,運行的速度也就越慢。因此,需要在RDBMS的隔離性需求和性能之間協調。
MySQL默認為REPEATABLE READ隔離級,這個隔離級適用於大多數應用程序,只有在應用程序有具體的對於更高或更低隔離級的要求時才需要改動。沒有一個標准公式來決定哪個隔離級適用於應用程序——大多數情況下,這是一個主觀的決定,它是基於應用程序的容錯能力和應用程序開發者對於潛在數據錯誤的影響的判斷。隔離級的選擇對於每個應用程序也是沒有標准的。例如,同一個應用程序的不同事務基於執行的任務需要不同的隔離級。
作者 tianyazaiheruan