目錄
1,事務的詳細介紹
2,事務的屬性
3,事務常見的操作方式
1,事務的詳細介紹
????????在MySQL數據庫中,事務是指一組SQL語句作為一個指令去執行相應的操作,這些操作要么全部成功提交,對數據庫產生影響;要么全部失敗回滾(撤銷當前事務所做的更改),不對數據庫產生任何影響。事務確保了數據庫的一致性和完整性,即保證了不同的客戶端看到的數據是不相同的,以下是事務的通俗說明:
????????事務就是要做的或所做的事情,主要用于處理操作量大,復雜度高的數據。假設一種場景:你畢業了,學校的教務系統后臺 MySQL 中,不在需要你的數據,要刪除你的所有信息,那么要刪除你的基本信息(姓名,電話,籍貫等)的同時,也刪除和你有關的其他信息,比如:你的各科成績等。這樣,就需要多條 MySQL 語句構成,那么所有這些操作合起來,就構成了一個事務。
? ? ? ? 為什么要有事務呢?事務本質是為了當應用程序訪問數據庫的時候,事務能夠簡化我們的編程模型,不需要我們去考慮各種各樣的潛在錯誤和并發問題。事務不僅保證了數據的一致性和完整性,還提高了系統的可靠性。通過正確地使用事務,可以有效地管理和維護數據庫的狀態。總的來說,事務是數據庫管理系統中不可或缺的一部分。
????????注意:在 MySQL 中,只有使用了 Innodb 存儲引擎的數據庫或表才支持事務。
2,事務的屬性
????????一個 MySQL 數據庫上,可不止一個事務在運行,同一時刻,甚至有大量的請求被包裝成事務,在向 MySQL 服務器發起事務處理請求。而每條事務至少一條 SQL,甚至有更多個 SQL,如果大家都訪問同樣的表數據,在不加保護的情況,就絕對會出現問題。因為事務由多條 SQL 構成,所以這里就會出現很多問題,比如 SQL 執行到一半出錯或中途停止往后執行的情況。因此,一個完整的事務,絕對不是簡單的 sql 集合,還擁有四個屬性:
- 原子性:事務是一個不可分割的工作單位,要么全部完成,要么全部不完成,不會在中間某個環節結束。若事務在執行過程中發生錯誤,它就會被回滾到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
- 一致性:在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、關聯性,以及后續數據庫可以自發性地完成事先預定的工作。
- 隔離性:一個事務所做的修改在最終提交以前,對其它事務是不可見的。數據庫允許多個并發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務并發執行時由于交叉執行而導致數據的不一致。
- 持久性:事務處理結束后,其所做的修改就會永久保存在數據庫中。
????????事務的四個屬性可以簡稱為 ACID。
3,事務常見的操作方式
1,事務的提交方式
????????事務的提交方式常見的有兩種:自動提交和手動提交。
????????自動提交意味著每執行完一條語句,MySQL 會自動將更改指令提交到數據庫,使更改永久化。自動提交方式下,這里的每個單獨 SQL 語句都被視為一個獨立的事務,在執行后會立即被提交到數據庫。
? ? ? ? 手動提交意味著,在你執行一系列的 SQL 語句之后,需要手動執行指令(commit指令)來提交事務,使所有更改生效。具體的流程后面運用時會說明。? ?
查看事務的提交方式:show variables like 'autocommit';
? ? ? ? 上面圖中,ON表示自動提交,OFF表示手動提交。默認情況下是自動提交(ON)。?
修改事務的提交方式,用 set 指令:set autocommit=0;? ? ? ?
說明:0表示禁止自動提交,1表示開啟自動提交????????????????????????????????????????????????????????
? ? ? ? 注意:上面操作選擇手動提交和自動提交時,僅是對當前會話的操作,其它終端啟動時仍是MySQL 默認的情況。?
2,事務的隔離
????????事務的隔離是指事務的隔離性,它確保了不同的事務在并發執行時不會互相干擾。事務的隔離并不是將所有的數據都隔離,因為不同的事務之間可能存在聯系,因此,在數據庫中,允許事務受不同程度的干擾,就有了一種重要特征:隔離級別。
????????MySQL支持四種標準的事務隔離級別:
????????讀未提交:這是最低的隔離級別,在這個級別上,事務可以讀取未被其他事務提交的數據,這可能會出現臟讀,即一個事務能夠看到另一個事務尚未提交的更改,導致事務讀取到的數據是一個臨時數據或錯誤數據。(實際生產中不可能使用這種隔離級別的,它相當于沒有提供事務間的隔離)
????????讀提交:事務只能讀取已經被其他事務提交的數據,也就是說事務沒有提交之前,其它正在運行的事務都是看不到的。這種隔離級別會引起不可重復讀,也就是同一個事務在不同時間點讀取同一行數據可能會得到不同的結果,例如:事務A提交了數據,那么事務B就會看到已經被事務A修改過的數據,原本的數據已經被修改了。
????????可重復讀:這是 MySQL 默認的隔離級別。在這個級別上,一個事務在執行中,多次讀取操作數據時,會看到同樣的數據行,即使其他事務對數據進行了修改并提交。這意味著在一個事務開始后,它將不會看到其他事務所做的任何更改,從而避免了不可重復讀的問題。不過,在此隔離級別下,仍然可能存在幻讀問題,即在同一事務中兩次查詢可能得到不同的行集合,通常是因為其他事務插入了記錄(其他事務的插入操作,可重復讀無法屏蔽其操作)。例如:事務A提交了數據,事務B看到的數據仍然是最開始的數據,即便事務A修改了此數據,除非結束事務B。
????????串行化:這是事務的最高隔離級別,它通過強制事務排序,使之不可能相互沖突, 從而解決了幻讀的問題。具體操作是,它在每個讀取操作上都會加上共享鎖,導致事務按順序執行,這會極大地降低性能,并發度最低,因為可能會導致超時和鎖競爭。(這種隔離級別太極端,實際生產基本不使用)
3,設置事務的隔離級別
? ? ? ? 四種隔離級別:READ UNCOMMITTED(讀未提交)、READ COMMITTED(讀已提交)、REPEATABLE READ(可重復讀)、SERIALIZABLE(可串行化)。默認情況下,MySQL數據庫對應的是REPEATABLE READ(可重復讀)
查看當前會話的事務隔離級別(只影響當前連接):
? ? ? ? select @@transaction_isolation;
查看全局的事務隔離級別(整個MySQL服務器采用的事務隔離級別,也是所有新連接的默認設置):
????????select @@global.transaction_isolation;
設置當前會話的事務隔離級別
? ? ? ? set session transaction isolation level [隔離的四種級別];
設置全局的事務隔離級別
? ? ? ? set global transaction isolation level?[隔離的四種級別];
4,事務的操作流程
? ? ? ? MySQL運用事務時,具體的詳細流程是:
? ? ? ? 1,根據需求,選擇事務的隔離級別,MySQL默認是REPEATABLE READ(可重復讀)。
? ? ? ? 2,查看事務的提交方式,根據需求進行設置。默認情況下的提交方式是自動提交,一條單獨的 SQL 語句就是一個獨立的事務,直接 SQL 指令操作即可,如同平常的一般操作。如果你希望執行一系列操作作為一個整體(也就是一個事務),然后進行提交,那么就需要使用手動提交。下面的操作流程都是按照手動提交的方式進行的,自動提交沒有任何流程。
????????3,開啟一個事務。需注意,使用指令開啟一個新事務時,這隱含地使用手動提交方式,即set autocommit=0;(關閉自動提交),但不會改變全局或會話變量的實際值,也就是說使用?show variables like 'autocommit'; 查看到的提交方式仍沒有變化。
(除非你顯式設置)。
開啟一個事務:start transaction; 或 begin;? ? ? ? 此時的提交方式是手動提交
? ? ? ? 4,設置保存點。保存點可根據需求自由選擇設置。在復雜的事務中,可能需要部分回滾。MySQL允許你在事務中設置保存點,然后選擇性地回滾到某個保存點。至于保存點的釋放也是可選擇的,因為 MySQL 在事務結束后會自動釋放未釋放的保存點。
設置保存點:savepoint [保存點名稱];
釋放保存點:release savepoint [保存點名稱];
例如:
????????創建一個保存點save1:savepoint save1;? ? ?
????????釋放保存點save1:release savepoint save1;
? ? ? ? 5,執行事務中的 SQL 操作。這里就開始進行?SQL 操作了。
? ? ? ? 注意:4和5通常是一體的,即每次操作時,先設置保存點,然后指定 SQL 操作。
????????6,回滾事務。回滾操作也是自由選擇的操作。該操作是為了防止事務在處理過程中所發生的錯誤。回滾操作分為兩類:1,回滾到事務開始的最初狀態,即撤銷事務中的所有操作。2,選擇性地回滾到某個保存點,即回滾到某一個保存點所保存的指令。
回滾到最初狀態:rollback;
回滾到保存點:rollback to [保存點名稱];
例如:rollback to?save2; ? ? ?回滾到保存點save2
? ? ? ? 7,提交事務。當你完成了事務中的所有操作,就可以提交對事務所做的操作了,即手動提交,結束事務。這時,事務中的所有更改都會被保存到數據庫中。
提交事務:commit
? ? ? ? 下面來以具體的樣例說明:
創建一個 test 表:create table test(id int primary key,name varchar(50));
查看提交方式:show variables like 'autocommit';
開始一個事務:begin;
創建一個保存點save1:savepoint save1;
插入一條記錄:insert into test values (1, '李白');
創建一個保存點save2:savepoint save2;
插入一條記錄:insert into test values (2, '杜甫');
查看操作:select * from test;? ? ?數據已經存在,但沒有commit,此時只是在該終端下查看
回滾到保存點save2:rollback to save2;
再次查看:select * from test;? ? ? ?此時沒有(2,'杜甫')的記錄,因為發生了回滾
回滾在最開始:rollback;? ? ? ? ? ? ?此時再次查看發現一條記錄也沒有了
????????注意:事務的操作過程中,當操作異常時,MySQL會自動回滾。
? ? ? ? 事務的隔離底層往往是運用相應的鎖來控制。隔離級別越嚴格,安全性就越高,但數據庫的并發性能也就越低,實際情況中往往需要在兩者之間找一個平衡點。
????????如果系統運行發生中斷,使某個事務尚未完成而被迫中斷,這時,使用 InnoDB 存儲引擎的MySQL 數據庫能夠通過其內置的日志和恢復機制來維護數據的一致性和完整性。對于未提交的事務,它會被回滾。
? ? ? ? 總結一下,不可重復讀的重點是修改和刪除,即同樣的條件,讀取過的數據再次讀取出來時,發現值不一樣了。幻讀的重點在于新增行,即同樣的條件,第1次和第2次讀出來的記錄數不一樣。MySQL 默認的隔離級別是可重復讀,一般情況下不要修改。