30.6. MySQL併發控制,加鎖和事務,隔離級別,日誌等

併發控制

鎖粒度:
表級鎖
行級鎖
鎖:
讀鎖:共享鎖,只讀不可寫(包括本身當前用戶和當前事務) ,多個讀互不阻塞
寫鎖:獨佔鎖,排它鎖,寫鎖會阻塞其它事務(不包括當前事務)的讀和它鎖
實現
存儲引擎:自行實現其鎖策略和鎖粒度
服務器級:實現了鎖,表級鎖,用戶可顯式請求
分類:
隱式鎖:由存儲引擎自動施加鎖
顯式鎖:用戶手動請求html

鎖策略:在鎖粒度及數據安全性尋求的平衡機制
顯式使用鎖mysql

  1. LOCK TABLES 加鎖
    lock tables tbl_name [[AS] alias] lock_type
    [, tbl_name [[AS] alias] lock_type] ...
    lock_type: READ ,WRITE
  2. UNLOCK TABLES 解鎖
  3. FLUSH TABLES [tb_name[,...]] [WITH READ LOCK]
    關閉全部正在打開的表,同時清除掉查詢緩存以及準備好的語句緩存,
    若是加上with read lock 選項的話,它表明關閉全部正在打開的表並加上全局鎖(不清除緩存了),一般在備份前加全局讀鎖
  4. SELECT clause [FOR UPDATE | LOCK IN SHARE MODE]
    查詢時加寫或讀鎖

注意點1(加鎖):

  1. 注意,讀鎖加到表上以後,此表將只能讀,不能進行其餘任何操做。並且加了讀鎖的這個session終端也不能對它進行讀read之外其餘操做了,必需要unlock table命令以後才能夠進行其餘操做。
    • 可是若是在此session上加了一個read鎖以後,再在此session上對其餘的一個或多個表再繼續加read鎖(沒有unlock tables),則通過測試以及查看lock的幫助得知,以前加的這個鎖將會被清除掉,只有最後一個鎖會生效。
    • 對於其餘的session終端來講,只有最後一個表至關於被加了read鎖,以前在原來的session被加鎖的表的鎖都會消失掉,和沒加鎖效果同樣。而對於原來的session來講也是這樣,只不過通過測試,若是想要訪問以前被加過鎖可是掉鎖的表的時候,它會報錯(不管是select命令仍是其餘命令都會報錯,其餘終端session上不會報錯)
    • 此時在原session上只有unlock table 以後纔可繼續訪問以前的被加鎖可是掉鎖的表而不報錯。
    • 通過測試 lock table TABNAME write 的結果和上面read的效果相同,只不過它倆限制的內容不同而已,上面說的現象都是lock tables這個命令的效果,和加讀鎖read仍是寫鎖write無關;
    • 還有一點要注意的是,若是在當前session中對錶加了鎖以後,當前session終端上退出了mysql的鏈接(注意不是關閉了終端,就是當前終端上退出數據庫的鏈接,固然關閉終端更加暴力),則這個鎖就當即失效了,其餘的終端session上就能夠繼續進行正常訪問數據庫了。(同時加鎖也是當即生效的,並且這個鎖都是全局當即生效的,注意這個效果和以前的global變量不一樣:global變量雖然也是全局的,但它必須重連session才能生效,這個加鎖解鎖都是命令一執行則全部鏈接的session不用從新鏈接就全局直接當即生效了。
  2. flush tables with read lock:這個命令和lock table仍是有區別的,並且有一點很是重要
    • 當在一個session中,先用了lock table命令鎖了本身想要鎖定的表,此時若是在再當前session開啓事務,則注意,這些用命令lock table命令被鎖的表上面的鎖所有都會被釋放,就至關於執行了unlock tables,同時,其餘session以前不能執行的操做或者正在執行可是阻塞的操做(好比這邊session開了讀鎖,另外的session要插入數據可是卡住,而此時這邊的session又開了事務,則另外的session中的這個插入命令就直接執行併成功了,並且可以瞬間被這邊的事務看到,事務級別爲可重複讀的級別。估計是由於測試用的插入命令就一條執行很快,若是插入修改等命令佔用時間過多的話可能在這邊事務中就看不到那麼多的內容了)
    • 而flush tables with read lock命令則不會受到事務開啓的影響,由於它不含table lock。開啓事務以後,用這個命令執行的全局鎖仍然會生效。不過固然,若是當前鏈接到數據庫的session退出,這個全局鎖也會失效。也能夠手動unlock tables取消這個全局鎖。
    • 更詳細的說明查看官方文檔
      https://dev.mysql.com/doc/refman/5.7/en/flush.html#flush-tables-with-read-lock
    • 下面三段話的解釋說明,(結合示例):
FLUSH TABLES WITH READ LOCK acquires a global read lock rather than table locks, so it is not subject to the same behavior as LOCK TABLES and UNLOCK TABLES with respect to table locking and implicit commits:

UNLOCK TABLES implicitly commits any active transaction only if any tables currently have been locked with LOCK TABLES. The commit does not occur for UNLOCK TABLES following FLUSH TABLES WITH READ LOCK because the latter statement does not acquire table locks.

Beginning a transaction causes table locks acquired with LOCK TABLES to be released, as though you had executed UNLOCK TABLES. Beginning a transaction does not release a global read lock acquired with FLUSH TABLES WITH READ LOCK.

注意:unlock tables 命令只能解當前session加的鎖sql

  1. flush不受到lock命令的影響,前者獲得的鎖和後者獲得的鎖不同:
  2. unlock tables命令會把當前session中的事務給提交commit了,由於它隱性的執行了commit命令,注意不過有個前提就是數據庫中有表被lock tables 命令鎖住了,此時執行unlock tables纔會commit,若是沒有表被鎖,執行unlock tables命令至關於無效,沒有執行任何操做。
    • 注意上面已經說過了,開啓事務會把開始事務以前的table lock給解開,所以1中的狀況指的是開啓事務以後,再次進行了lock table的命令進行了加鎖(不管是給哪一個表加鎖都同樣),此時若是事務沒有完成可是進行了unlock tables命令操做,則它至關於即進行了解鎖,但會也把當前事務給提交commit了,(注意unlock提交以後再進行的操做就不在以前的事務內了)這點及其要注意。
    • 附加:若是對錶加了寫鎖,若沒有對錶進行更改,其餘的session仍是能用select查看此表的,由於用了緩存,緩存驗證表滅有改變,其餘session還能查看。可是若是當前session對錶進行修改了,則緩存驗證不經過,其餘session就會卡住沒法對錶進行包括查看以內的任何命令了。
  3. 對於flush tables加的鎖,則unlock tables 雖然可以解鎖,可是不會把事務給提交了。
    • 注意 lock tables和flush tables加鎖通過測試不可以同時存在
    • 好比先flush tables(不管是事務前仍是事務後),由於它會加了全局讀鎖以後就沒法再用lock table命令給表加鎖了。
    • 再好比,先lock tables以後,而後再flush tables加全局鎖,它會提示Can't execute the given command because you have active locked tables or an active transaction。
  4. 一些結果的例子:
    • 先lock鎖再開啓事務,則lock鎖直接無效
    • 先事務,再開啓lock鎖,鎖有效,可是若是在當前的客戶端中解鎖,則會一併把事務給提交commit了(注意不是回滾),事務就結束了。
    • flush的加鎖全局有效,此時開啓事務沒有意義(只能讀),它的功能最好之久就是僅僅用於備份
    • 根據上面操做得知,要對錶進行獨佔操做,先開啓事務,再開啓寫鎖,順序不能反
  5. 還有一點就是,在session的事務中,一旦session斷開(quit數據庫或直接關閉窗口),若是加了lock鎖 則至關於此session的執行了unlock table命令,但由於unlock tables它會隱性的執行commit命令 ,會將鎖所有解開並自動提交事務,所以會讓這個session斷開之間的事務的已經進行的操做給commit了,這點要注意當心
    可是若是此session並未加鎖,則session斷開則至關於當前事務執行了rollback操做。

事務

事務Transactions:一組原子性的SQL語句,或一個獨立工做單元
事務日誌:記錄事務信息,實現undo,redo等故障恢復功能數據庫

  • ACID特性:
    1. A:atomicity原子性;整個事務中的全部操做要麼所有成功執行,要麼所有失敗後回滾
    2. C:consistency一致性;數據庫老是從一個一致性狀態轉換爲另外一個一致性狀態
    3. I:Isolation隔離性;一個事務所作出的操做在提交以前,是不能爲其它事務所見;隔離有多種隔離級別,實現併發
    4. D:durability持久性;一旦事務提交,其所作的修改會永久保存於數據庫中

事務的生命週期

image

事務隔離級別

  • 事務隔離級別:從上至下嚴格程度遞增
    1. READ UNCOMMITTED 可讀取到未提交數據,產生髒讀
    2. READ COMMITTED 可讀取到提交數據,但未提交數據不可讀,產生不可重複讀,便可讀取到多個提交數據,致使每次讀取數據不一致
    3. REPEATABLE READ 可重複讀,屢次讀取數據都一致,產生幻讀,即讀取過程當中,即便有其它提交的事務修改數據,仍只能讀取到未修改前的舊數據。此爲MySQL默認設置
    4. SERIALIZABILE 可串行化,未提交的讀事務阻塞修改事務,或者未提交的修改事務阻塞讀事務。致使併發性能差
  • MVCC: 多版本併發控制,和事務級別相關

image

事務的相關操做

  1. 啓動事務:
    BEGIN;
    BEGIN WORK;
    START TRANSACTION;
  2. 結束事務:
    COMMIT:提交
    ROLLBACK: 回滾
    注意:只有事務型存儲引擎中的DML語句方能支持此類操做,好比innodb。(myisam不支持)
  3. 自動提交:set autocommit={1|0}
    默認爲1,爲0時設爲非自動提交
    建議:顯式請求和提交事務,而不要使用「自動提交」功能
  4. 事務支持保存點:savepoint
    SAVEPOINT identifier;
    ROLLBACK [WORK] TO [SAVEPOINT] identifier;
    RELEASE SAVEPOINT identifier;

指定事務隔離級別:

服務器變量tx_isolation指定,默認爲REPEATABLE-READ,可在GLOBAL和
SESSION級進行設置

SET tx_isolation=''
READ-UNCOMMITTED
READ-COMMITTED
REPEATABLE-READ
SERIALIZABLE
也可在服務器選項中指定,重啓服務自動生效
vim /etc/my.cnf
[mysqld]
transaction-isolation=SERIALIZABLEvim

  • 注:mysql默認的事務級別(可重複讀,也叫幻讀)很符合生產要求,通常不須要修改

併發控制

  1. 死鎖:
    兩個或多個事務在同一資源相互佔用,並請求鎖定對方佔用的資源的狀態
  2. 事務日誌:
    事務日誌的寫入類型爲「追加」,所以其操做爲「順序IO」 ;一般也被稱爲:預寫式日誌 write ahead logging
    事務日誌文件: ib_logfile0, ib_logfile1

注意點2(事務):

  1. 事務對於數據庫中的數據操做過程:開啓事務以後,首先將事務讀入內存之中,而後對它進行的各類操做會同步寫入事務日誌中,此時由於並未寫入真正的數據存放文件位置內,所以能夠進行回滾等操做。等到事務內的全部操做所有完成並提交以後,數據此時才真正的修改了。
    • 若是在這個過程當中出現故障或者其餘問題,則服務器下次正常重啓(也有多是客戶端斷開了未提交事務)的時候,事務日誌發現上一次進行的事務並未完成,則它就會對這個事務已經進行的操做undo,進行rollback回滾操做。
    • 而若是重啓以後事務日誌發現上一次的事務的操做已經在內存中處理完畢了(事務完整而且提交結束了),可是對於數據的修改還未真正進行或者說僅僅執行了一部分,則事務日誌就會對這個事務進行redo操做,從新執行事務。
  2. 事務的原子性和一致性:一個或者多個事務若是在執行過程當中中斷,則下次機器或者服務正常啓動的時候,會先對事務日誌進行查詢處於執行一半過程當中的事務的操做將會回滾被撤銷掉,而那些以前完成的事務(並未寫入磁盤)則將會寫入到磁盤上,這樣就能保證事務操做的事件的原子性,要麼作完事務內的這一系列操做,要麼這些操做一個都不作。
  3. 注意,Mysql數據庫默認就自動提交,每一條單獨命令都是一個獨立的事務,每執行一條語句,就至關於執行了 ‘語句 ;commit;’ 的隱性2個操做(DDL語句更特殊,它不是至關於執行,它就是隱性跟着commit語句並執行它,下面有介紹)。
    • 由此緣由,在以前進行的各類測試中,由於沒有使用顯式事務(手動開啓事務),所以對數據庫進行的何種操做都至關於單條命令事務,只要一執行就至關於提交了會當即生效就可以在其餘的session中看到結果(好比建立數據庫,建立表這些DDL語言,以及DML語言增長刪除記錄等等,都會當即生效被其餘session看到)
    • 能夠經過修改配置或變量autocommit爲off來關閉自動提交事務
    • 但若是手動開啓了顯式事務,則在這個顯式事務內的命令就不會自動提交了,必須手動commit提交(除了DDL語句以外)。
    • 可是注意了DDL語言(create,drop,alter),就算是在事務中,好比說手動begin開啓事務或者說把autocommit設置爲off以後,它的結果也會當即生效,感受就像直接就commit了DDL語句,即便當前是在事務內;並且感受真的沒錯,通過測試,只要進行了DDL語句的命令,它後面就隱性地真的執行了commit命令並結束了當前事務,後面的命令就不在當前事務內了(若是mysql按照默認的配置自動提交,則此時後面執行DML的操做也就是單命令事務了,也就會當即生效並在其餘session可見了),
    • 由上面DDL的特殊性可知,在事務中前面執行的DML語句就算沒有commit或者rollback,只要後面再跟上一個DDL語句就會把這個整個事務給提交了,很容易形成前面不想提交的DML語句被提交而且永久生效了。所以在事務中不能混用DML和DDL。
    • 還有一點就是手動開啓事務begin會把以前加的table鎖解開,可是autocommit模式下,若是不手動開啓事務,雖然執行一條命令自動提交了(看起來像執行了'begin 命令 commit'),可是這個隱性的begin事務不像顯式的手動begin開啓事務,它並不會把lock table的鎖給解開,因此放心使用
  4. 一個事務的結束用commit或者rollback命令,不管是這兩個的哪個命令被執行了,都會結束當前事務;
    • 注意執行了上面兩個命令以後,當前事務就結束了,在mysql的默認配置下(自動提交),若是以後沒有再手動開啓事務的話,則再進行的操做就至關於自動提交的單條事務了(至關於從新鏈接到mysql數據庫時的初始狀態,沒有手動開啓任何顯式事務),而這樣就會在其餘session中可見到當即生效的結果。
    • 還有要注意,若是在事務中用了savepoint 保存點, 利用rollback to savepoint_name命令,並無結束當前事務,後面的命令仍然在事務中執行,只有最後遇到commit或者rollback命令纔會結束事務並提交或回滾。注意它和rollback的區別:後者直接結束當前事務。
  5. 注意事務的隔離級別的做用範圍是兩個不一樣的事務之間,好比兩個新開的session都手動開啓了begin顯式事務,這兩個事務處於隔離級別中;而若是沒有開啓begin顯式事務的話,好比新開兩個session但沒有輸入begin,則不屬於隔離級別做用範圍。
    • 注意事務隔離級別的變量和服務器選項不相同。
    • 注意在事務以內的查詢select命令不會被緩存到查詢緩存中,只會增長not_cache中的數量(若是能存進去則其餘session和事務就能夠查詢到了,就起不到隔離級別的效果了)
  6. 在可重複讀的隔離級別中:一個session的一個事務提交commit並結束以後,而後利用了select 命令查看了一下。此時若是在另外的事務中用相同的select命令查看,則這一次查看通過對查詢緩存的status變量分析得知:
    - 第一點:首先咱們要知道,查詢緩存的緩存內容,在鏈接到數據庫的任何一個session中,不管是在開啓的顯性事務內仍是沒有開啓事務,只要對錶進行了DML語句(經測試DDL語句不影響),則此mysql數據庫以前的全部緩存過的SQL語句queries_in_cache都會被清空爲0(不修改不會清空)(不過那些統計的變量不會被清空)。
    • 還有一點就是,在一個事務內的進行的select語句查詢操做,若是在全部的session開啓事務以後,全部的session都沒有進行過DML語句,這在這個事務內的select的SQL語句也會被記錄到查詢緩存中,不過這個查詢緩存是相對於總的數據庫來講的,和這個事務無關。能夠這樣說,標準情況下,一個事務內的select查詢語句原本是不會被記錄到查詢緩存中的,事務內的select語句只會增長not-cached的數量,但在這裏會被記錄到查詢緩存queries_in_cache中是由於這個事務雖然begin手動開啓了,可是並無執行修改數據的DML操做,也就至關於沒有開啓事務。執行的查詢操做被系統認爲在事務外,因此會被記錄到查詢緩存中
    • 在以上兩點的前提下,回到以前的問題,在開啓的顯性事務中第一個的select查看命令(不論在事務以前是否有徹底同樣的SQL語句),即便在可重複讀隔離級別下,這整個事務的第一次的select查看語句都可以查看到當前表的真實數據狀態。
    • 能夠這樣理解,也就是說,這一個事務,雖然begin開啓的時間很早,但只要你沒有使用selec命令進行查看,則這個事務就至關於沒有開啓,只有在事務內使用了查看select命令的時候,這個可重複讀的事務才至關於剛剛開啓,以前的其餘事務即便是在這個事務的begin命令以後的操做,也可以被這第一個select命令查看到。
    • 根據上面的緣由,當可重複讀事務內執行select命令以後,才能把它看作是真正的開啓了事務,以後的select纔有幻讀的隔離效果,此時若是其餘的session再開啓事務,而後進行操做,即便它提交併進行了查看命令,也不會再影響這個事務的查看了。這裏毫不能把begin看作開啓事務的起點時間。通過了各類測試,確實是這樣的結果。
    • 注意可重複讀級別中,上面這裏的事務中的第一次select語句雖然看到當前數據庫表中真正的數據,但這裏真正的數據指的是已經被其餘事務commit修改後的永久保存後的結果,若是其餘事務尚未提交併修改數據爲永久的(也就是說其餘事務可以回滾),則這個select是看不到的,必定要分清楚哪些能看到,哪些不能看到。還要區分可重複讀和不可重複讀以及上面提到的這一點坑的區別
    • 上面是經屢次測試總結下來,目前就是這樣結果,更多內容更多之後再研究。
    • 若是利用事務進行備份而又不想影響到其餘客戶進行修改或者查詢操做等,不能用flush tables的方式(固然在這裏其餘客戶不能進行DDL操做),則就用幻讀的隔離級別事務來進行這種備份操做,進去以後必定要先執行一次select命令真正開啓事務再進行備份。
  7. Innodb存儲引擎,事務開啓以後,各個事務則會對錶中正在修改(DML)的行record進行加鎖操做,此時若是有兩個事務想要修改已經被對方事務加鎖的row記錄的話(也就是對方事務以前已經對這些行進行了DML操做了,加了鎖,注意這些行能夠是數據庫中同一個表的不一樣行,也但是不一樣表的不一樣行),則就會產生死鎖現象(若是僅僅是一個事務想要修改被另外的事務中加鎖的表中的行row的話,只是會卡住而已)。
    • 此時若是服務器發現死鎖現象存在,就會將其中的一個事務進行rollback操做,僅讓一個事務生效。
  8. 若是出現了一個表長期被鎖致使其餘用戶沒法操做,可用show processlist以及和kill命令來剔除鎖表的用戶和命令(主要是sleep的用戶要踢掉,他可能就是鎖表的用戶,沒有進行操做還連着數據庫)
  9. 事務日誌是比數據寫入磁盤中要先寫的,也被稱爲預寫式日誌。它是按照追加的方式寫入默認的兩個事務日誌文件中的,這兩個事務日誌文件默認就在存放數據庫數據的目錄中(可修改)。這兩個(或多個)事務日誌文件一個文件寫滿了就會寫另一個,另一個也寫滿了就會從新返回來寫這個文件,把以前的日誌給覆蓋掉。

日誌

事務日誌 transaction log
錯誤日誌 error log
通用日誌 general log
慢查詢日誌 slow query log
二進制日誌 binary log
中繼日誌 reley log緩存

事務日誌

事務日誌:transaction log
事務型存儲引擎自行管理和使用,建議和數據文件分開存放
redo log
undo log
Innodb事務日誌相關配置:
show variables like '%innodb_log%';
innodb_log_file_size 5242880 每一個日誌文件大小
innodb_log_files_in_group 2 日誌組成員個數
innodb_log_group_home_dir ./ 事務文件路徑(能夠寫絕對路徑)
innodb_flush_log_at_trx_commit 默認爲1安全

  1. innodb_flush_log_at_trx_commit
    說明:設置爲1,同時sync_binlog = 1表示最高級別的容錯
    innodb_use_global_flush_log_at_trx_commit的值肯定是否可使用SET語句重置此變量
    • 1默認狀況下,日誌緩衝區將寫入日誌文件,並在每次事務後執行刷新到磁盤。這是徹底遵照ACID特性
    • 0提交時沒有任何操做; 而是每秒執行一第二天志緩衝區寫入和刷新。 這樣能夠提供更好的性能,但服務器崩潰能夠清除最後一秒的事務
    • 2每次提交後都會寫入日誌緩衝區,但每秒都會進行一次刷新。 性能比0略好一些,但操做系統或停電可能致使最後一秒的交易丟失
    • 3模擬MariaDB 5.5組提交(每組提交3個同步),此項MariaDB 10.0支持

事務日誌優化:

image

錯誤日誌

  1. 錯誤日誌
    mysqld啓動和關閉過程當中輸出的事件信息
    mysqld運行中產生的錯誤信息
    event scheduler運行一個event時產生的日誌信息
    在主從複製架構中的從服務器上啓動從服務器線程時產生的信息
  2. 錯誤日誌相關配置
    SHOW GLOBAL VARIABLES LIKE 'log_error'
    錯誤文件路徑
    log_error=/PATH/TO/LOG_ERROR_FILE
    是否記錄警告信息至錯誤日誌文件
    log_warnings=1|0 默認值1

通用日誌

  1. 通用日誌:記錄對數據庫的通用操做,包括錯誤的SQL語句
    文件:file,默認值
    表:table
  2. 通用日誌相關設置
    general_log=ON|OFF
    general_log_file=HOSTNAME.log
    log_output=TABLE|FILE|NONE

慢查詢日誌

慢查詢日誌:記錄執行查詢時長超出指定時長的操做
slow_query_log=ON|OFF 開啓或關閉慢查詢
long_query_time=N 慢查詢的閥值,單位秒
slow_query_log_file=HOSTNAME-slow.log 慢查詢日誌文件
log_slow_filter = admin,filesort,filesort_on_disk,full_join,full_scan,
query_cache,query_cache_miss,tmp_table,tmp_table_on_disk
上述查詢類型且查詢時長超過long_query_time,則記錄日誌
log_queries_not_using_indexes=ON 不使用索引或使用全索引掃描,不論
是否達到慢查詢閥值的語句是否記錄日誌,默認OFF,即不記錄
log_slow_rate_limit = 1 多少次查詢才記錄,mariadb特有
log_slow_verbosity= Query_plan,explain 記錄內容
log_slow_queries = OFF 同slow_query_log 新版已廢棄服務器

二進制日誌

  1. 二進制日誌
    記錄致使數據改變或潛在致使數據改變的SQL語句
    記錄已提交的日誌
    不依賴於存儲引擎類型
    功能:經過「重放」日誌文件中的事件來生成數據副本
    注意:建議二進制日誌和數據文件分開存放
  2. 中繼日誌:relay log
    主從複製架構中,從服務器用於保存從主服務器的二進制日誌中讀取的事件session

  3. 二進制日誌記錄格式
    • 二進制日誌記錄三種格式
      基於「語句」記錄:statement,記錄語句,默認模式
      基於「行」記錄:row,記錄數據,日誌量較大
      混合模式:mixed, 讓系統自行斷定該基於哪一種方式進行
  4. 格式配置
    show variables like ‘binlog_format';
  5. 二進制日誌文件的構成
    有兩類文件
    日誌文件:mysql|mariadb-bin.文件名後綴,二進制格式
    如: mariadb-bin.000001
    索引文件:mysql|mariadb-bin.index,文本格式
  6. 二進制日誌相關的服務器變量:
    • sql_log_bin=ON|OFF:是否記錄二進制日誌,默認ON
    • log_bin=/PATH/BIN_LOG_FILE:指定文件位置;默認OFF,表示不啓用二進制日誌功能,上述兩項都開啓纔可
    • binlog_format=STATEMENT|ROW|MIXED:二進制日誌記錄的格式,默認STATEMENT
    • max_binlog_size=1073741824:單個二進制日誌文件的最大致積,到達最大值會自動滾動,默認爲1G
      說明:文件達到上限時的大小未必爲指定的精確值
    • sync_binlog=1|0:設定是否啓動二進制日誌即時同步磁盤功能,默認0,由操做系統負責同步日誌到磁盤,1的話是當即寫入磁盤,雖然更加安全可是IO效率佔用多,影響服務器效率
    • expire_logs_days=N:二進制日誌能夠自動刪除的天數。 默認爲0,即不自動刪除
  7. 二進制日誌相關配置
    • 查看mariadb自行管理使用中的二進制日誌文件列表,及大小
      SHOW {BINARY | MASTER} LOGS
    • 查看使用中的二進制日誌文件
      SHOW MASTER STATUS
    • 查看二進制文件中的指定內容
      SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]
      show binlog events in ‘mysql-bin.000001' from 6516 limit 2,3

二進制日誌工具

mysqlbinlog:二進制日誌的客戶端命令工具架構

  1. 命令格式:
    mysqlbinlog [OPTIONS] log_file…
    --start-position=# 指定開始位置
    --stop-position=#
    --start-datetime=
    --stop-datetime=
    時間格式:YYYY-MM-DD hh:mm:ss
    --base64-output[=name]
    -v -vvv :查看詳細信息
    示例:
    mysqlbinlog --start-position=6787 --stop-position=7527 /var/lib/mysql/mariadb-bin.000003 -v
    mysqlbinlog --start-datetime="2018-01-30 20:30:10" --stop-datetime="2018-01-30 20:35:22" mariadb-bin.000003 -vvv

  2. 二進制日誌事件的格式:
    #at 328
    #151105 16:31:40 server id 1 end_log_pos 431 Query thread_id=1 exec_time=0 error_code=0
    use mydb/!/;
    SET TIMESTAMP=1446712300/!/;
    CREATE TABLE tb1 (id int, name char(30))
    /!/;

事件發生的日期和時間:151105 16:31:40
事件發生的服務器標識:server id 1
事件的結束位置:end_log_pos 431
事件的類型:Query
事件發生時所在服務器執行此事件的線程的ID:thread_id=1
語句的時間戳與將其寫入二進制文件中的時間差:exec_time=0
錯誤代碼:error_code=0
事件內容:
GTID:Global Transaction ID,mysql5.6以mariadb10以上版本專屬屬性:GTID

  1. 清除指定二進制日誌:
    PURGE { BINARY | MASTER } LOGS { TO 'log_name' | BEFORE datetime_expr }
    示例:
    PURGE BINARY LOGS TO ‘mariadb-bin.000003’;刪除3以前的日誌
    PURGE BINARY LOGS BEFORE '2017-01-23';
    PURGE BINARY LOGS BEFORE '2017-03-22 09:25:30';
    • 刪除全部二進制日誌,index文件從新記數:
      RESET MASTER [TO #];
      刪除全部二進制日誌文件,並從新生成日誌文件,文件名從#開始記數,默認從1開始,通常是master主機第一次啓動時執行,
      MariaDB10.1.6開始支持TO #
    • 切換日誌文件:
      FLUSH LOGS;
      注意它會Closes and reopens any log file to which the server is writing.
      所以雖然它也能生成新的二級制文件,不過最好仍是單獨用命令flush binary logs;

注意點3(日誌)

  1. 各類日誌的位置,大小,啓用的功能等等參數都有相應的變量以及服務器選項配置用於修改。
  2. 事務日誌可用innodb_log_group_home_dir 選項在配置文件中修改其存放的位置,最好是把它和數據庫目錄分開存放,這樣能夠提升數據庫的讀寫IO速度,減小IO佔用。
    • 事務日誌有多種把最終的修改後的事務數據寫入磁盤的方式,能夠用變量(選項)innodb_flush_log_at_trx_commit的值來控制。若是爲提升效率,能夠把它修改成2.不過注意可能有丟失事務操做的數據的風險(不過通常這種風險比較小,由於斷電都有額外供電電源,只有CPU或者mysql崩了纔會出現問題)
  3. 通用日誌默認不啓用,能夠直接global變量修改general_log=on啓動,默認位置也和數據庫放在一塊兒,也能夠修改默認位置和名字 general_log_file
    • 通用日誌除了上面的以文件方式存放,也能夠以表的形式存放,修改選項log_output的值便可.若是以表的形式存放,則這個表的位置就在mysql的database下,名字就叫general_log;
  4. 慢查詢日誌能夠查看哪些任務的查詢速度很慢,再用explain從新執行這些命令,查看是否沒有利用索引等,以及再根據其餘的操做來判斷爲什麼這個操做速度慢(命令不合理仍是數據庫的表設計不合理等,或者說沒有建立索引,用於甩鍋,慢查詢所以很重要)
    • 除了打開慢查詢,調整一下時間長度,設置文件位置,還有一個選項log_queries_not_using_indexes打開,則可讓查詢只要沒有用索引的記錄都用慢查詢記錄下來。以上幾項比較經常使用。
  5. 二進制的日誌只記錄已經提交的事務或者說是已經完成的數據操做,而事務日誌不論提交與否都會記錄下來事務中進行的各類操做。
    • 二進制日誌只記錄數據的增刪改操做,至於查詢以及對服務器的配置操做(修改變量和選項等,目前所知這種操做它不記錄的,由於沒有對數據進行操做,能夠查看官方文檔來詳細分析,由於這個修改配置可能會影響後面的主從服務器的同步問題,但這裏暫時當作所有都不記錄)都不記錄。注意它會記錄受權以及建立用戶的操做等等,由於這些操做至關因而對information和mysql數據庫的內容進行了修改。
    • 二進制日誌主要用於恢復上次全備份以後到服務器崩潰之間這一段時間內的數據操做,也用來進行主從備份。所以二進制日誌很重要,同時它不要和原來的數據庫文件放在一塊兒,要分開硬盤存放,也要把它進行遠程主機的備份。
  6. 二級制日誌基於語句形式的話會形成根據時間情況的命令執行的錯誤(好比now())函數等等),所以最好用基於row的方式記錄二進制日誌,不過這樣的話也會形成二進制日誌所佔空間的增加速度比數據庫還要快,它要比數據庫的文件還要大。也能夠用mixd模式來進行記錄減小一點影響。不過最好是用row的格式來記錄。
  7. 二進制日誌有兩項控制變量必須都開啓纔可,其中sql_log_bin是爲了在mysql鏈接以後的session命令行中直接控制二進制是否記錄用的,在某些狀況下(好比主從備份,還原數據的時候等等,由於數據變了可是不想讓它記錄到二進制日誌中)會把它關閉來進行一些設置以後再開啓。
    • 另一個log_bin選項,若是在配置文件中直接寫入,它會生成二進制文件在數據庫中,也能夠用它本身指定二進制文件的路徑位置。生產中最好就是用這個選項把二進制日誌文件放到其餘目錄中,可是注意別忘了二進制文件目錄的屬主(其餘日誌改位置也是)。
    • 只要重啓mysql服務,就會生成一個新的二進制文件(重啓的時候至關於執行了flush binary logs命令)
  8. 利用mysqlbinlog查看的二進制文件的標準輸出(加上-v或者不加都行,重定向導出的時候最好不加),它的結果也能夠直接導出到文件中,好比起個名字叫bin.sql 這個文件也能夠直接導入到數據庫中進行數據的恢復操做。
    • 用這種方式的好處就是能夠選取二進制文件中記錄的部分操做(利用start,stop等選開始結束點,不寫結束點的話就是到最後),而後進行恢復。固然也能夠直接把這整個二進制文件進行導入數據庫的操做,和sql的導入方式是同樣的,mysql數據庫也支持。
    • 到這裏咱們發現已經有4種文件能夠直接導入了,一個是咱們本身寫的sql文件,裏面就是各個sql語句;一個是二進制文件直接導入;一個是二進制文件部分導入,先利用mysqlbinlog查看的結果生成一個文件而後把它重定向導入;還有一個是後面的mysqldump命令生成的sql文件,它相似於本身寫的sql文件,不過它是數據庫的邏輯全盤備份文件,後面博客詳細介紹。
  9. 二進制文件的清理操做:
    • 在進行清理操做以前可用flush binary logs新建二進制文件,而後再用purge命令清除以前的二進制文件(能夠指定日期等)
    • 利用reset master [to #] 能夠清除全部的binarylogs而且從數字#開始,不寫默認爲1,它和flush的不一樣之處就是它會刪除掉全部的二進制文件,慎用。
    • 在不鏈接數據庫的狀況下用mysqladmin flush-binary-logs也能夠切換新的binlog.

下面是配置文件中,可能要配置的設置,先放在這裏之後完善詳細設置:

[服務器端]
注意各個日誌文件夾的屬主

datadir
socket
port
safe update 開啓
per table 開啓
sql_mode 嚴格模式
服務器字符集設置utf8mb4
慢查詢,時間閾值,位置,利用索引記錄打開
通用日誌,位置
事務日誌,大小,數量,位置,開啓2模式等
查詢緩存開啓,大小,每一個字節設置等等,優化
pid-log
log-err
二進制日誌,位置

[客戶端]
字符集utf8mb4
socket
datadir
prompt="Date:\D Count:\c \n\U[\d] > "


下面是測試用sql語句文件,可寫入文件後直接導入數據庫。

create table testlog (id int auto_increment primary key,name char(10),age int default 20);

delimiter $$

create procedure  pro_testlog() 
begin  
declare i int;
set i = 1; 
while i < 100000 
do  insert into testlog(name,age) values (concat('wang',i),i); 
set i = i +1; 
end while; 
end$$

delimiter ;
相關文章
相關標籤/搜索