數據庫 之 事務控制和隔離級別
事務是指一組原子性的SQL查詢、或者是一個或多個SQL語句組成的獨立工作單元;MyISAM不流行的原因很大是因為其不支持事務的處理功能。
2 事務日誌
事務日誌定義屬性,有些參數可以運行時修改,寫入在配置段裏,事務日誌相當於是中間的輔助功能,而且很關鍵。
事務日誌表示把操作過程一筆一筆記錄下來。如某個線程要對某個行操作,數據庫會先保留老版本於事務日誌中,對文件的寫入,新版本的內容是先寫入到日誌裏,提交前,數據在日誌文件中,而不是在數據文件中,提交操作執行後,才將新舊版本的日誌清除。
執行事務時,每個操作都需要從內存讀入到日誌中
事務日誌主要是為了加速操作,同時為了輔助提交數據的功能,將隨機寫操作轉換為順序寫操作
事務日誌必須是固定大小,一般是有兩個空間,一旦一個空間滿了,就寫入磁盤,另一個空間開始寫入。輪替工作。
為了避免事務日誌所在的磁盤,因硬盤故障導致破壞,可以用raid或者鏡像組同步寫入兩份文件,保證了冗余,實現數據安全
以下是配置文件裏事務日誌的相關參數:
innodb_log_files_in_group:表示一組內有幾個文件,一般要有兩個
innodb_log_group_home_dir:指明家目錄
innodb_log_file_size:指定日誌文件的大小,默認5M
innodb_mirrored_log_groups:日誌組有幾個
3 ACID測試
如果一個存儲引擎支持事務,那麽關系型數據庫就必須滿足ACID測試:而非關系型數據庫是base(堿性的單詞)
A:AUTOMICITY,原子性;整個事務中的所有操作要麽全部成功執行,要麽全部失敗後回滾到開始處;
C:CONSISTENCY,一致性;數據庫總是應該從一個一致性狀態轉為另一個一致性狀態;
I:ISOLATION,隔離性;一個事務所做出的操作在提交之前,是否能為其它事務可見;出於保證並發操作之目的,隔離有多種級別; 隔離如果做得嚴格,可能導致串行執行,而失去了並發執行的意義。有四個級別,隔離性最低,並發性最高,隔離性最高,安全性也最高,但是並發性就最低。可以根據安全性和服務器的並發性選擇一個合適的方案。
D:DURABILITY,持久性;事務一旦提交,其所做出的修改會永久保存;
4 事務控制
自動提交:單語句事務,影響性能
mysql> SELECT @@autocommit;#查看自動提交功能參數
mysql> SET @@session.autocommit=0;#關閉自動提交功能後需要手動控制事務
手動控制事務,事務一旦提交,就不能回滾:
啟動事務:START TRANSACTION
提交事務:COMMIT
回滾事務:ROLLBACK
事務支持savepoints:保存點,相當於是虛擬機的快照
SAVEPOINT identifier#創建保存點
ROLLBACK [WORK] TO [SAVEPOINT] identifier #還原到某個保存點
RELEASE SAVEPOINT identifier#銷毀savepoint
例子
MariaDB [sunny]> insert into classlist values ("su",10,"91"),("chen",18,"88");MariaDB [sunny]>
#創建保存點first
MariaDB [sunny]> savepoint first;
MariaDB [sunny]> update classlist set name=ghbsunny where nu=1;
#創建保存點second
MariaDB [sunny]> saveponit second;
如果不修改nu=1的name值,此時執行
MariaDB [sunny]> rollback to first;
#註意,執行完 rollback to first保存點second就不存在了,因為在保存點first的時候,second還沒創建。一旦執行了commint後,就不能rollback
#銷毀保存點first
MariaDB [sunny]> release savepoint first;
5 事務隔離級別
級別由低而高,最高級別是串行化。隔離性越來越好,但是並發性降低。低級別的事務一定有高級別的問題
mysql數據庫默認是第三隔離級別REPEATABLE-READ,其他數據庫一般默認第二級別READ-COMMITTED,所以mysql建議也修改為第二級別的READ-COMMITTED
查看當前會話級定義的事務隔離級別
MariaDB [sunny]> select @@session.tx_isolation;
mysql有四個隔離級別,如下:
READ-UNCOMMITTED:
讀未提交 --> 容易導致臟讀,不被確認的結果也可能被讀取;即沒有提交的情況下,別人也可以看到未提交的更新的記錄
例子:打開兩個crt窗口,登錄mysql,分別關閉自動提交功能和設置隔離級別為READ-UNCOMMITTED
MariaDB [sunny]> SET @@session.autocommit=0;
MariaDB [sunny]> set @@session.tx_isolation="READ-UNCOMMITTED";
MariaDB [sunny]> start transaction;
在窗口1上執行
MariaDB [sunny]> update classlist set name="bf" where nu=10;
此時,窗口1沒有執行commit,但是在窗口2上能夠看到已經更新後的數據,即窗口2上執行如下語句,看到nu=10的name已經更改為bf了,即窗口2可以隨時看到窗口1的任何修改
MariaDB [sunny]> select * from classlist where nu=10;
+------+----+-------+
| name | nu | score |
+------+----+-------+
| bf | 10 | 91.00 |
+------+----+-------+
READ-COMMITTED:
讀提交--> 讀別人確認的數據,可能導致不可重復讀的問題,可能多次讀的結果不一樣;
例子:打開兩個crt窗口,登錄mysql,分別關閉自動提交功能和設置隔離級別為READ-COMMITTED
MariaDB [sunny]> SET @@session.autocommit=0;
MariaDB [sunny]> set @@session.tx_isolation="READ-COMMITTED";
MariaDB [sunny]> start transaction;
在窗口1上執行
MariaDB [sunny]> delete from classlist where nu=1;
此時,窗口1沒有執行commit操作,窗口1上查看到的nu=1已經被刪除,但是查看2還是可以看到nu=1的記錄
窗口2上執行如下
MariaDB [sunny]> select * from classlist where nu=1;
+-------+----+--------+
| name | nu | score |
+-------+----+--------+
| sunny | 1 | 100.00 |
+-------+----+--------+
1 row in set (0.00 sec)
窗口1上執行commit後,窗口2頁查看不到記錄
REPEATABLE-READ:
可重復讀,mysql數據庫默認的隔離級別 --> 導致幻讀的問題,如別的事務已經修改過數據,但是看到的還是舊數據;
例子:打開兩個crt窗口,登錄mysql,分別關閉自動提交功能和設置隔離級別為READ-COMMITTED
MariaDB [sunny]> SET @@session.autocommit=0;
MariaDB [sunny]> set @@session.tx_isolation="REPEATABLE-READ";
MariaDB [sunny]> start transaction;
在窗口1上執行
MariaDB [sunny]> insert into classlist values ("mei",5,99);
此時還沒commit,在窗口1上可以看到新增的數據,但是窗口2上看不到新增加的數據
在窗口1上執行
MariaDB [sunny]> commit;
此時,窗口1上任然可以看到新增加的數據,但是窗口2上看不到新增的nu=5的數據,
窗口2以為沒有nu=5的數據,但是窗口2要插入nu=5的數據,會出現報錯重復數據的提示
MariaDB [sunny]> insert into classlist values ("mei2",5,98);
ERROR 1062 (23000): Duplicate entry '5' for key 'PRIMARY'
MariaDB [sunny]> select * from classlist;
+----------+----+-------+
| name | nu | score |
+----------+----+-------+
| sunny | 1 | 98.00 |
| chao | 3 | 98.00 |
| tracy su | 6 | 95.00 |
+----------+----+-------+
如果要看到新增的數據,窗口2可以退出sql窗口,重新登錄,就可以看到新增nu=5的數據
SERIALIZABLE:
串行化,隔離度最高;只有對方的事務結束(要麽commit,要麽rollback),另一窗口才能執行對同一表格的操作
例子:打開兩個crt窗口,登錄mysql,分別關閉自動提交功能和設置隔離級別為READ-COMMITTED
MariaDB [sunny]> SET @@session.autocommit=0;
MariaDB [sunny]> set @@session.tx_isolation="SERIALIZABLE";
MariaDB [sunny]> start transaction;
在窗口1上執行如下語句,但是不執行commit;自己操作後,沒有確認,則別人也不能查看該表,因為已經該表瑣死。只能在自己提交會回滾後,別人才能查詢到結果。
delete from classlist where nu=8;
此時在窗口2上執行如下語句,那麽窗口2的查詢結果就出不來,等待時間超時後,就會出現報錯
MariaDB [sunny]> select * from classlist;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
數據庫 之 事務控制和隔離級別