MySQL 事務功能node
==============================================================================mysql
1.介紹
ios
★事務:nginx
一組原子性的SQL查詢、或者是一個或多個SQL語句組成的獨立工做單元;sql
★ACID測試:數據庫
☉A:AUTOMICITY,原子性;緩存
整個事務中的全部操做要麼所有成功執行,要麼所有失敗後回滾;bash
☉C:CONSISTENCY,一致性;session
數據庫老是應該從一個一致性狀態轉爲另外一個一致性狀態;併發
☉I:ISOLATION,隔離性;
一個事務所作出的操做在提交以前,是否能爲其它事務可見;出於保證併發操做之目的,隔離有多種級別;
☉D:DURABILITY,持久性;
事務一旦提交,其所作出的修改會永久保存;
2.事務日誌:
mysql會最大程度的使用緩存機制來提升數據庫的訪問效率,可是萬一數據庫發生斷電,由於緩存的數據沒有寫入磁盤,致使緩存在內存中的數據丟失而致使數據不一致怎麼辦?
★Innodb主要是經過事務日誌實現ACID特性;
★事務日誌包括:
☉重作日誌redo
Redo記錄的是已經所有完成的事務,就是執行了commit(提交)的事務,記錄文件是ib_logfile0 ib_logfile1;
☉回滾日誌undo
Undo記錄的是已部分完成而且寫入硬盤的未完成的事務,默認狀況下回滾日誌是記錄在表空間中的(共享表空間或者獨享表空間);
★執行過程:
通常狀況下,mysql在崩潰以後,重啓服務,innodb經過回滾日誌undo將全部已完成並寫入磁盤的未完成事務進行rollback,而後redo中的事務所有從新執行一遍(後臺啓動相關線程自動執行)便可恢復數據,可是隨着redo的量增長,每次從redo的第一條開始恢復就會浪費長的時間,因此引入了checkpoint(檢查點)機制;
★事務日誌相關配置參數:
innodb_log_files_in_group //一組中有幾個文件,默認爲2個
innodb_log_group_home_dir //日誌目錄的存放位置,默認在數據目錄中
innodb_log_file_size //日誌文件大小
innodb_mirrored_log_groups //鏡像日誌組
演示:
1.查看事物日誌相關的參數
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%innodb%log%'; +-------------------------------------------+---------+ | Variable_name | Value | +-------------------------------------------+---------+ | innodb_flush_log_at_trx_commit | 1 | 要不要在提交時從內存中同步數據到事物日誌所在磁盤上,1表示ON開啓 | innodb_locks_unsafe_for_binlog | OFF | | innodb_log_block_size | 512 | | innodb_log_buffer_size | 8388608 | | innodb_log_file_size | 5242880 | 日誌文件大小,默認爲5M | innodb_log_files_in_group | 2 | 一組中有幾個文件,默認爲2個 | innodb_log_group_home_dir | ./ | 日誌目錄的存放位置,默認在數據目錄中 | innodb_mirrored_log_groups | 1 | 鏡像日誌組(本身) | innodb_recovery_update_relay_log | OFF | | innodb_use_global_flush_log_at_trx_commit | ON | +-------------------------------------------+---------+ 10 rows in set (0.00 sec)
3.自動提交:單語句事務
★自動提交:單語句事務
默認狀況下mysql開啓的是單語句事物功能(即每一次執行完成後都會自動提交至事物日誌中,而後再從日誌中同步到數據文件中,很是影響性能),咱們要想手動控制事物,就要把自動提交事物的功能關閉。
★查看自動提交命令:
mysql> SELECT @@autocommit;
mysql> SHOW GLOBAL|SESSION VARIABLES LIKE 'autocommit'
★關閉當前會話單語句功能:
mysql> SET @@session.autocommit=0;
演示:
1.爲了演示效果,支持事物功能,我這裏修改了以前hellodb.sql的存儲引擎爲InnoDB,並從新導入mysql;如今,咱們要想手動控制事物,就須要關閉單語句事物功能,以下:
MariaDB [hellodb]> show table status like 'students'\G *************************** 1. row *************************** Name: students Engine: InnoDB # 存儲引擎爲InnoDB Version: 10 Row_format: Compact Rows: 25 Avg_row_length: 655 Data_length: 16384 Max_data_length: 0 Index_length: 0 Data_free: 0 Auto_increment: 26 Create_time: 2016-11-28 11:42:19 Update_time: NULL Check_time: NULL Collation: utf8_general_ci Checksum: NULL Create_options: Comment: 1 row in set (0.02 sec) MariaDB [hellodb]> SHOW VARIABLES LIKE 'autocommit'; # 查看當前會話的單語句事物功能爲ON +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.00 sec) MariaDB [hellodb]> SET @@session.autocommit=0; Query OK, 0 rows affected (0.01 sec) MariaDB [hellodb]> SHOW VARIABLES LIKE 'autocommit'; # 再次查看變爲OFF +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | OFF | +---------------+-------+ 1 row in set (0.01 sec)
--------------------------------------------------------------------------------
4.手動控制事務:
★啓動:START TRANSACTION
★提交:COMMIT
★回滾:ROLLBACK
★事務支持 savepoints:
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier
演示:
1.在關閉單語句事務的基礎上,手動啓動事物功能,並演示回滾操做
MariaDB [hellodb]> START TRANSACTION; # 啓動事物功能 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> DESC courses; +----------+----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+----------------------+------+-----+---------+----------------+ | CourseID | smallint(5) unsigned | NO | PRI | NULL | auto_increment | | Course | varchar(100) | NO | | NULL | | +----------+----------------------+------+-----+---------+----------------+ 2 rows in set (0.01 sec) MariaDB [hellodb]> SELECT * FROM courses; +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | +----------+----------------+ 7 rows in set (0.01 sec) MariaDB [hellodb]> INSERT INTO courses (Course) VALUES ('Zabbix'),('Puppet'); # 插入一行數據 Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 MariaDB [hellodb]> SELECT * FROM courses; +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 8 | Zabbix | | 9 | Puppet | +----------+----------------+ 9 rows in set (0.00 sec) MariaDB [hellodb]> DELETE FROM courses WHERE CourseID=3; # 刪除一行數據 Query OK, 1 row affected (0.00 sec) MariaDB [hellodb]> SELECT * FROM courses; +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 8 | Zabbix | | 9 | Puppet | +----------+----------------+ 8 rows in set (0.00 sec) MariaDB [hellodb]> ROLLBACK; # 若是這時咱們後悔了,能夠執行回滾操做 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> SELECT * FROM courses; # 查看能夠發現又會到原來開始的狀態了 +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | +----------+----------------+ 7 rows in set (0.00 sec)
2.在操做上添加savepoints(存儲點),能夠指定回滾到存儲點的位置,以下:
MariaDB [hellodb]> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> INSERT INTO courses (Course) VALUES ('Zabbix'),('Puppet'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 MariaDB [hellodb]> SAVEPOINT first; # 添加第一個存儲點 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> DELETE FROM courses WHERE CourseID=3; Query OK, 1 row affected (0.00 sec) MariaDB [hellodb]> SAVEPOINT second; # 添加第二個存儲點 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> UPDATE courses SET Course='nginx' WHERE CourseID=4; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 MariaDB [hellodb]> SELECT * FROM courses; # 查看修改後的表數據 +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 4 | nginx | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 10 | Zabbix | | 11 | Puppet | +----------+----------------+ 8 rows in set (0.00 sec) MariaDB [hellodb]> ROLLBACK TO second; # 回滾到第二個存儲點 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> SELECT * FROM courses; +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 10 | Zabbix | | 11 | Puppet | +----------+----------------+ 8 rows in set (0.00 sec) MariaDB [hellodb]> ROLLBACK TO first; Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> SELECT * FROM courses; # 回滾到第一個存儲點 +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 10 | Zabbix | | 11 | Puppet | +----------+----------------+ 9 rows in set (0.01 sec) MariaDB [hellodb]> ROLLBACK; # 回滾到原始狀態 Query OK, 0 rows affected (0.01 sec) MariaDB [hellodb]> SELECT * FROM courses; +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | +----------+----------------+ 7 rows in set (0.00 sec)
3.啓動事物,執行操做後提交(COMMIT),發現再回滾就無效了,由於這時已經同步到數據中了;
MariaDB [hellodb]> START TRANSACTION; # 啓動事物 Query OK, 0 rows affected (0.01 sec) MariaDB [hellodb]> INSERT INTO courses (Course) VALUES ('Zabbix'),('Puppet'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 MariaDB [hellodb]> COMMIT; # 提交 Query OK, 0 rows affected (0.01 sec) MariaDB [hellodb]> SELECT * FROM courses; # 提交後查看數據 +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 12 | Zabbix | | 13 | Puppet | +----------+----------------+ 9 rows in set (0.00 sec) MariaDB [hellodb]> ROLLBACK; Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> SELECT * FROM courses; # 執行回滾命令後發現無效 +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 12 | Zabbix | | 13 | Puppet | +----------+----------------+ 9 rows in set (0.00 sec)
5.事務隔離級別:
★事務隔離級別:
READ-UNCOMMITTED:讀未提交 --> 髒讀;
READ-COMMITTED:讀提交--> 不可重複讀;
REPEATABLE-READ:可重複讀 --> 幻讀;(默認級別)
SERIALIZABLE:串行化;
★查看及設定事物隔離級別:
mysql> SELECT @@session.tx_isolation;
mysql> SET @@session.tx_isolation='...'
演示:
1.READ-UNCOMMITTED:讀未提交 --> 髒讀;即當node1和node2兩個會話同時訪問修改同一張表時,node1用戶的事物尚未提交,node2用戶就能夠看到,致使的結果就是髒讀(看到了別人沒能提交的數據),以下:
1)在node1會話中,修改隔離級別爲讀未提交,而後啓動事物,修改一行數據,並回滾
MariaDB [hellodb]> SELECT @@tx_isolation; # 查看隔離級別 +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) MariaDB [hellodb]> SET @@session.tx_isolation='READ-UNCOMMITTED'; # 修改隔離級別爲讀未提交 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> SELECT @@tx_isolation; +------------------+ | @@tx_isolation | +------------------+ | READ-UNCOMMITTED | +------------------+ 1 row in set (0.00 sec) MariaDB [hellodb]> START TRANSACTION; # 啓動事物 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> UPDATE courses SET Course='nginx' WHERE CourseID=4; # 修改數據 Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 MariaDB [hellodb]> select * from courses; +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | nginx | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 12 | Zabbix | | 13 | Puppet | +----------+----------------+ 9 rows in set (0.00 sec) MariaDB [hellodb]> rollback; Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> select * from courses; # 回滾後查看數據 +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 12 | Zabbix | | 13 | Puppet | +----------+----------------+ 9 rows in set (0.00 sec)
2)在node2會話中能夠發現,它沒有作任何操做,先後兩次查看時數據發生了變化,因此讀未提交能夠看到別人沒能提交的數據
MariaDB [hellodb]> set @@session.tx_isolation='READ-UNCOMMITTED'; # 一樣設置運行級別爲讀未提交 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> SELECT @@tx_isolation; +------------------+ | @@tx_isolation | +------------------+ | READ-UNCOMMITTED | +------------------+ 1 row in set (0.00 sec) MariaDB [hellodb]> start transaction; # 一樣啓動事物 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> select * from courses; # node1會話修改數據後查看,能夠看到修改的數據nginx +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | nginx | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 12 | Zabbix | | 13 | Puppet | +----------+----------------+ 9 rows in set (0.01 sec) MariaDB [hellodb]> select * from courses; # node1會話執行回滾後查看,能夠看到又爲原來的狀態 +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 12 | Zabbix | | 13 | Puppet | +----------+----------------+ 9 rows in set (0.00 sec)
2.READ-COMMITTED:讀提交--> 不可重複讀;即當node1和node2兩個會話同時訪問修改同一張表時,node1用戶的事物只有提交了,node2用戶才能夠看到,但node2用戶並無修改數據。因此,node2會話若是重複讀的話,每次的結果多是不同的,以下:
1)在node1會話中,修改隔離級別爲讀提交,而後啓動事物,修改一行數據,並提交;
MariaDB [hellodb]> set @@session.tx_isolation='READ-COMMITTED'; #修改隔離級別爲讀提交 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> SELECT @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | READ-COMMITTED | +----------------+ 1 row in set (0.00 sec) MariaDB [hellodb]> start transaction; # 啓動事物 Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> UPDATE courses SET Course='Nagios' WHERE CourseID=12; # 修改數據 Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 MariaDB [hellodb]> select * from courses; +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 12 | Nagios | | 13 | Puppet | +----------+----------------+ 9 rows in set (0.00 sec) MariaDB [hellodb]> COMMIT; # 提交數據 Query OK, 0 rows affected (0.01 sec)
2)在node2會話中,能夠發如今node1會話未提交數據以前,node2查看到的數據一直沒有發生改變,直到node1會話提交數據以後,node2才發現數據發生了改變,但node2沒有作任何操做
MariaDB [hellodb]> set @@session.tx_isolation='READ-COMMITTED'; Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> start transaction; Query OK, 0 rows affected (0.00 sec) MariaDB [hellodb]> SELECT * FROM courses; # 在node1會話沒有提交數據前,數據爲改變 +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 12 | Zabbix | | 13 | Puppet | +----------+----------------+ 9 rows in set (0.00 sec) MariaDB [hellodb]> SELECT * FROM courses; # node1會話提交數據後,能夠看到數據發生改變 +----------+----------------+ | CourseID | Course | +----------+----------------+ | 1 | Hamo Gong | | 2 | Kuihua Baodian | | 3 | Jinshe Jianfa | | 4 | Taiji Quan | | 5 | Daiyu Zanghua | | 6 | Weituo Zhang | | 7 | Dagou Bangfa | | 12 | Nagios | | 13 | Puppet | +----------+----------------+ 9 rows in set (0.00 sec) MariaDB [hellodb]> COMMIT; Query OK, 0 rows affected (0.00 sec)
3.REPEATABLE-READ:可重複讀 --> 幻讀,也是mysql和mariadb的默認運行級別,即兩個會話爲各自獨立的事務。node1和node2會話只要創建事務,第一次查看數據的結果將貫穿整個事物過程當中,期間底層數據的變化是看不到的,只有在結束事物後才能夠看到數據的變化,這樣直接致使的結果就是幻讀,即各自會話看到的數據並不是真實的數據,底層數據可能已經發生了改變;