MySQL總結

1. 數據庫引擎

MySQL默認有多款數據庫引擎,默認使用的是InnoDB.介紹一下InnoDB和MyISAM.html

1.1 InnoDB

  • 支持事務安全java

    事務四大特徵(ACID)
    原子性(A):要麼都成功,要麼都失敗mysql

    一致性(C):保證沒有數據更新會執行到一半而致使和其餘數據不統一sql

    隔離性(I):事務A和事務B之間具備隔離性數據庫

    持久性(D):是事務的保證,事務終結的標誌(內存的數據持久到硬盤文件中)緩存

  • 爲處理巨大數據量而設計安全

    它的CPU效率肯能是任何其餘基於磁盤的關係數據庫引擎所不能匹敵的性能優化

  • 將表和索引在一個邏輯表空間中
  • 支持外鍵
  • 被用在衆多須要高性能的大型數據庫站點上服務器

1.2 MyISAM

擁有較高的插入、查詢速度、但不支持事務數據結構

  • 在支持大文件的文件系統和操做系統上被支持
  • 表最大索引64,每一個索引最大的列數16
  • 最大的鍵長度是1000B
  • BLOB和TEXT能夠被索引
  • null值被容許在索引的列中
  • 能夠把數文件和索引文件放在不一樣目錄
  • 每一個字符列能夠有不一樣的字符集
  • 有VARCHAR的表能夠固定或動態記錄長度
  • VACHAR和CHAR列能夠多達64KB

1.3 存儲引擎的選擇

大多數狀況下選擇默認的InnoDB便可

2. 索引

對數據庫表中一列或多列的值進行排序的一種結構,

使用索引可提升數據庫中特定數據的查詢速度

2.1 含義和特色

  • 類型

    • BTREE

      INNODB和MyISAM引擎只支持BTREE

    • HASH

      MEMORY/HEAP引擎只支持HASH

  • 優勢

    • 惟一索引可保證數據庫表中每一行數據的惟一性.
    • 大大加快查詢速度
    • 能夠加速表和表之間的鏈接
    • 可顯著減小分組和排序的時間.
  • 缺點

    • 建立和維護索引要消耗時間
    • 佔磁盤空間
    • 對錶中數據CUD時,索引也要動態的維護,耗時

2.2 分類

  • 普通索引和惟一索引

    普通索引: 可插入重複值和空值

    惟一索引: 列值必須惟一,但可有空值

    組合索引: 列值的組合必須惟一

    主鍵索引: 特殊的惟一索引,不容許空值

  • 單列索引和組合索引

    單列索引: 一個索引只包含單個列,一個表能夠有多個單列索引.

    組合索引: 多個字段組合建立的索引.在查詢中使用了這些字段的左邊字段時,索引纔會被引用

  • 全文索引

    全文索引:
    • FULLTEXT,列值支持全文查找,可存入空值和重複值,

    • 能夠建立在char、varchar或text類型的列上

  • 空間索引

    空間索引:

    • 對空間數據類型字段創建的因此呢
    • 四種空間類型: GEPMETRY POINT LINESTRING POLYGON
    • 使用SPQTIAL關鍵字擴展建立正規索引的語法來建立空間so因
    • 列必須爲NOT NULL,只能在MyISAM的表中建立

2.3 設計原則

  • 索引並不是越多越好,佔空間、影響CUD性能
  • 不對常常更新的表進行過多的索引,並使索引的列儘量少,但對常常查詢的字段建立索引.
  • 數據量小不要使用索引
  • 在條件表達式中不一樣值多的列上創建索引.
  • 惟一的值使用惟一索引
  • 頻繁排序或分組的列上創建索引.

3. 性能優化

經過SQL語句查詢、數據結構和硬件三個方面進行優化.

3.1 查詢

show status like 'value' 查詢數據庫性能參數.

value 能夠替換爲:

  • Connections 鏈接次數
  • Uptime 上線時間
  • Slow_queries 慢查詢次數
  • Com_select 查詢的次數
  • Com_insert 插入操做的次數
  • Com_update 更新操做的次數
  • Com_delete 刪除操做的次數

  • 分析查詢語句

    explain/describe/desc select select_options

  • 使用索引提升查詢速度
  • 使用索引查詢

    • 使用LIKE關鍵字的查詢語句(%在第一個位置索引不會起做用)
    • 使用多列索引的查詢語句(假如一個索引由a、b、c三個字段組成,必須使用a字段,查詢時才能使索引生效,最多包含16個字段)

    • 使用OR關鍵字的查詢語句(查詢條件只有or,且or先後的兩個條件中的列都是索引時,查詢中才使用索引.不然查詢將不使用索引)

  • 優化子查詢

    子查詢雖然可使查詢語句很靈活,可是執行效率不高.

    可使用JOIN查詢代替子查詢,鏈接查詢不須要創建臨時表,速度比子查詢快.

3.2 數據庫結構

  • 將字段不少的表分解成多個表

    將使用頻率很低的表拆解出來.

  • 增長中間表

    對於常常須要聯合查詢的表,能夠創建中間表提升查詢效率.

    給常常查詢的字段創建一箇中間表,並將原來聯合查詢的表的數據插入到中間表中.之後就可使用中間表來查詢了

  • 增長冗餘字段

    合理地加入冗餘字段能夠提升查詢速度.

    經過在冗餘字段上加入本身須要聯合查詢才能查出來的值,這樣避免聯合查詢提升效率

  • 優化插入記錄的速度

    • 禁用索引(MYSQL會根據表的索引對插入的記錄創建索引.創建索引有額外開銷)
    • 禁用惟一性檢查(理由和上面差很少)
    • 使用批量插入(一塊兒插入比一條一條 insert語句要快)
    • 使用LOAD DATA IN FILE批量導入(比insert快)
  • 分析表、檢查表和優化表

    • 分析表

      分析表: 分析關鍵字的分佈.

      ANALYZE TABLE  tbl_name;

      分析表的過程會加一個只讀鎖,分析期間只能讀,不能update&insert

    • 檢查表

      檢查表是否存在錯誤.

      除了表還能夠檢查視圖,也加只讀鎖

      CHECK TABLE tbl_name;

    • 優化表

      主要是消除刪除或者更新形成的空間浪費.

      經過OPTIMIZE TABLE能夠消除刪除和更新形成的文件素片.也會加鎖

      只能優化表中的VARCHAR、BLOB或TEXT類型的字段.

3.3 MySQL服務器

  • 優化服務器硬件

    • 配置較大的內存

      增長系統的緩衝區容量,使數據在內存停留的時間更長,以減小磁盤I/O

    • 配置高速磁盤系統
    • 合理分配磁盤I/O

      把磁盤I/O分散在多個設備上,減小資源競爭.提升並行操做

    • 配置更多處理器

      多處理器可同時執行多個線程

  • 優化MySQL參數

  • 修改back_log參數值:由默認的50修改成500.(每一個鏈接256kb,佔用:125M)
    back_log=500

back_log值指出在MySQL暫時中止回答新請求以前的短期內多少個請求能夠被存在堆棧中。也就是說,若是MySql的鏈接數據達到max_connections時,新來的請求將會被存在堆棧中,以等待某一鏈接釋放資源,該堆棧的數量即back_log,若是等待鏈接的數量超過back_log,將不被授予鏈接資源。將會報:unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待鏈接進程時.

back_log值不能超過TCP/IP鏈接的偵聽隊列的大小。若超過則無效,查看當前系統的TCP/IP鏈接的偵聽隊列的大小命令:cat /proc/sys/net/ipv4/tcp_max_syn_backlog目前系統爲1024。對於Linux系統推薦設置爲小於512的整數。

修改系統內核參數,)http://www.51testing.com/html/64/n-810764.html

查看mysql 當前系統默認back_log值,命令:

show variables like 'back_log'; 查看當前數量
  • 修改wait_timeout參數值,由默認的8小時,修改成30分鐘。(本次不用)
    wait_timeout=1800(單位爲妙)
我對wait-timeout這個參數的理解:MySQL客戶端的數據庫鏈接閒置最大時間值。

說得比較通俗一點,就是當你的MySQL鏈接閒置超過必定時間後將會被強行關閉。MySQL默認的wait-timeout  值爲8個小時,能夠經過命令show variables like 'wait_timeout'查看結果值;。

設置這個值是很是有意義的,好比你的網站有大量的MySQL連接請求(每一個MySQL鏈接都是要內存資源開銷的 ),因爲你的程序的緣由有大量的鏈接請求空閒啥事也不幹,白白佔用內存資源,或者致使MySQL超過最大鏈接數歷來沒法新建鏈接致使「Too many connections」的錯誤。在設置以前你能夠查看一下你的MYSQL的狀態(可用show processlist),若是常常發現MYSQL中有大量的Sleep進程,則須要 修改wait-timeout值了。

interactive_timeout:服務器關閉交互式鏈接前等待活動的秒數。交互式客戶端定義爲在mysql_real_connect()中使用CLIENT_INTERACTIVE選項的客戶端。

wait_timeout:服務器關閉非交互鏈接以前等待活動的秒數。在線程啓動時,根據全局wait_timeout值或全局 interactive_timeout值初始化會話wait_timeout值,取決於客戶端類型(由mysql_real_connect()的鏈接選項CLIENT_INTERACTIVE定義).

這兩個參數必須配合使用。不然單獨設置wait_timeout無效
  • 修改max_connections參數值,由默認的151,修改成3000(750M)。
    max_connections=3000
max_connections是指MySql的最大鏈接數,若是服務器的併發鏈接請求量比較大,建議調高此值,以增長並行鏈接數量,固然這創建在機器能支撐的狀況下,由於若是鏈接數越多,介於MySql會爲每一個鏈接提供鏈接緩衝區,就會開銷越多的內存,因此要適當調整該值,不能盲目提升設值。能夠過'conn%'通配符查看當前狀態的鏈接數量,以定奪該值的大小。

MySQL服務器容許的最大鏈接數16384;

查看系統當前最大鏈接數:

show variables like 'max_connections';
  • 修改max_user_connections值,由默認的0,修改成800
    max_user_connections=800
max_user_connections是指每一個數據庫用戶的最大鏈接

針對某一個帳號的全部客戶端並行鏈接到MYSQL服務的最大並行鏈接數。簡單說是指同一個帳號可以同時鏈接到mysql服務的最大鏈接數。設置爲0表示不限制。

目前默認值爲:0不受限制。

這兒順便介紹下Max_used_connections:它是指從此次mysql服務啓動到如今,同一時刻並行鏈接數的最大值。它不是指當前的鏈接狀況,而是一個比較值。若是在過去某一個時刻,MYSQL服務同時有1000個請求鏈接過來,而以後再也沒有出現這麼大的併發請求時,則Max_used_connections=1000.請注意與show variables 裏的max_user_connections的區別。默認爲0表示無限大。

查看max_user_connections值

show variables like 'max_user_connections';
  • 修改thread_concurrency值,由目前默認的8,修改成64
    thread_concurrency=64
thread_concurrency的值的正確與否, 對mysql的性能影響很大, 在多個cpu(或多核)的狀況下,錯誤設置了thread_concurrency的值, 會致使mysql不能充分利用多cpu(或多核), 出現同一時刻只能一個cpu(或核)在工做的狀況。

thread_concurrency應設爲CPU核數的2倍. 好比有一個雙核的CPU, 那thread_concurrency  的應該爲4; 2個雙核的cpu, thread_concurrency的值應爲8.

好比:根據上面介紹咱們目前系統的配置,可知道爲4個CPU,每一個CPU爲8核,按照上面的計算規則,這兒應爲:4*8*2=64

查看系統當前thread_concurrency默認配置命令:

 show variables like 'thread_concurrency';
  • 添加skip-name-resolve,默認被註釋掉,沒有該參數。
    skip-name-resolve
skip-name-resolve:禁止MySQL對外部鏈接進行DNS解析,使用這一選項能夠消除MySQL進行DNS解析的時間。但須要注意,若是開啓該選項,則全部遠程主機鏈接受權都要使用IP地址方式,不然MySQL將沒法正常處理鏈接請求!
  • skip-networking,默認被註釋掉。沒有該參數。(本次無用)
    skip-networking建議被註釋掉,不要開啓
開啓該選項能夠完全關閉MySQL的TCP/IP鏈接方式,若是WEB服務器是以遠程鏈接的方式訪問MySQL數據庫服務器則不要開啓該選項!不然將沒法正常鏈接!
  • default-storage-engine(設置MySQL的默認存儲引擎)
    default-storage-engine= InnoDB(設置InnoDB類型,另外還能夠設置MyISAM類型)
設置建立數據庫及表默認存儲類型

show table status like ‘tablename’顯示錶的當前存儲狀態值

查看MySQL有哪些存儲狀態及默認存儲狀態

 show engines;

建立表並指定存儲類型

CREATE TABLE mytable (id int, title char(20)) ENGINE = INNODB;

修改表存儲類型:

  Alter table tableName engine =engineName

 

備註:設置完後把如下幾個開啓:

# Uncomment the following if you are using InnoDB tables

innodb_data_home_dir = /var/lib/mysql

#innodb_data_file_path = ibdata1:1024M;ibdata2:10M:autoextend(要註釋掉,不然會建立一個新的把原來的替換的。)

innodb_log_group_home_dir = /var/lib/mysql

# You can set .._buffer_pool_size up to 50 - 80 %

# of RAM but beware of setting memory usage too high

innodb_buffer_pool_size = 1000M

innodb_additional_mem_pool_size = 20M

# Set .._log_file_size to 25 % of buffer pool size

innodb_log_file_size = 500M

innodb_log_buffer_size = 20M

innodb_flush_log_at_trx_commit = 0

innodb_lock_wait_timeout = 50

設置完後必定記得把MySQL安裝目錄地址(咱們目前是默認安裝因此地址/var/lib/mysql/)下的ib_logfile0和ib_logfile1刪除掉。不然重啓MySQL起動失敗。
  • 全局緩存
啓動MySQL時就要分配而且老是存在的全局緩存。目前有:key_buffer_size(默認值:402653184,即384M)、innodb_buffer_pool_size(默認值:134217728即:128M)、innodb_additional_mem_pool_size(默認值:8388608即:8M)、innodb_log_buffer_size(默認值:8388608即:8M)、query_cache_size(默認值:33554432即:32M)等五個。總共:560M.

這些變量值均可以經過命令如:show variables like '變量名';查看到。
  • key_buffer_size,本系統目前爲384M,可修改成400M

    key_buffer_size=400M
    ```
    key_buffer_size是用於索引塊的緩衝區大小,增長它可獲得更好處理的索引(對全部讀和多重寫),對MyISAM(MySQL表存儲的一種類型,能夠百度等查看詳情)表性能影響最大的一個參數。若是你使它太大,系統將開始換頁而且真的變慢了。嚴格說是它決定了數據庫索引處理的速度,尤爲是索引讀的速度。對於內存在4GB左右的服務器該參數可設置爲256M或384M.

怎麼才能知道key_buffer_size的設置是否合理呢,通常能夠檢查狀態值Key_read_requests和Key_reads ,比例key_reads / key_read_requests應該儘量的低,好比1:100,1:1000 ,1:10000。其值能夠用如下命令查得:show status like 'key_read%';

好比查看系統當前key_read和key_read_request值爲:

+-------------------+-------+

| Variable_name | Value |

+-------------------+-------+

| Key_read_requests | 28535 |

| Key_reads | 269 |

+-------------------+-------+

可知道有28535個請求,有269個請求在內存中沒有找到直接從硬盤讀取索引.

未命中緩存的機率爲:0.94%=269/28535*100%. 通常未命中機率在0.1之下比較好。目前已遠遠大於0.1,證實效果很差。若命中率在0.01如下,則建議適當的修改key_buffer_size值。

MyISAM、InnoDB、MyISAM Merge引擎、InnoDB、memory(heap)、archive

- innodb_buffer_pool_size(默認128M)

innodb_buffer_pool_size=1024M(1G)

innodb_buffer_pool_size:主要針對InnoDB表性能影響最大的一個參數。功能與Key_buffer_size同樣。InnoDB佔用的內存,除innodb_buffer_pool_size用於存儲頁面緩存數據外,另外正常狀況下還有大約8%的開銷,主要用在每一個緩存頁幀的描述、adaptive hash等數據結構,若是不是安全關閉,啓動時還要恢復的話,還要另開大約12%的內存用於恢復,二者相加就有差很少21%的開銷。假設:12G的innodb_buffer_pool_size,最多的時候InnoDB就可能佔用到14.5G的內存。若系統只有16G,並且只運行MySQL,且MySQL只用InnoDB,

那麼爲MySQL開12G,是最大限度地利用內存了。

另外InnoDB和 MyISAM 存儲引擎不一樣, MyISAM 的 key_buffer_size 只能緩存索引鍵,而 innodb_buffer_pool_size 卻能夠緩存數據塊和索引鍵。適當的增長這個參數的大小,能夠有效的減小 InnoDB 類型的表的磁盤 I/O 。

當咱們操做一個 InnoDB 表的時候,返回的全部數據或者去數據過程當中用到的任何一個索引塊,都會在這個內存區域中走一遭。

能夠經過 (Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests * 100% 計算緩存命中率,並根據命中率來調整 innodb_buffer_pool_size 參數大小進行優化。值能夠用如下命令查得:show status like 'Innodb_buffer_pool_read%';

好比查看當前系統中系統中

| Innodb_buffer_pool_read_requests | 1283826 |

| Innodb_buffer_pool_reads | 519 |

+---------------------------------------+---------+

其命中率99.959%=(1283826-519)/1283826*100% 命中率越高越好。

- innodb_buffer_pool_size(默認128M)

innodb_buffer_pool_size=1024M(1G)

innodb_buffer_pool_size:主要針對InnoDB表性能影響最大的一個參數。功能與Key_buffer_size同樣。InnoDB佔用的內存,除innodb_buffer_pool_size用於存儲頁面緩存數據外,另外正常狀況下還有大約8%的開銷,主要用在每一個緩存頁幀的描述、adaptive hash等數據結構,若是不是安全關閉,啓動時還要恢復的話,還要另開大約12%的內存用於恢復,二者相加就有差很少21%的開銷。假設:12G的innodb_buffer_pool_size,最多的時候InnoDB就可能佔用到14.5G的內存。若系統只有16G,並且只運行MySQL,且MySQL只用InnoDB,

那麼爲MySQL開12G,是最大限度地利用內存了。

另外InnoDB和 MyISAM 存儲引擎不一樣, MyISAM 的 key_buffer_size 只能緩存索引鍵,而 innodb_buffer_pool_size 卻能夠緩存數據塊和索引鍵。適當的增長這個參數的大小,能夠有效的減小 InnoDB 類型的表的磁盤 I/O 。

當咱們操做一個 InnoDB 表的時候,返回的全部數據或者去數據過程當中用到的任何一個索引塊,都會在這個內存區域中走一遭。

能夠經過 (Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests * 100% 計算緩存命中率,並根據命中率來調整 innodb_buffer_pool_size 參數大小進行優化。值能夠用如下命令查得:show status like 'Innodb_buffer_pool_read%';

好比查看當前系統中系統中

| Innodb_buffer_pool_read_requests | 1283826 |

| Innodb_buffer_pool_reads | 519 |

+---------------------------------------+---------+

其命中率99.959%=(1283826-519)/1283826*100% 命中率越高越好。

- innodb_additional_mem_pool_size(默認8M)

  innodb_additional_mem_pool_size=20M

innodb_additional_mem_pool_size 設置了InnoDB存儲引擎用來存放數據字典信息以及一些內部數據結構的內存空間大小,因此當咱們一個MySQL Instance中的數據庫對象很是多的時候,是須要適當調整該參數的大小以確保全部數據都能存放在內存中提升訪問效率的。

這個參數大小是否足夠仍是比較容易知道的,由於當太小的時候,MySQL會記錄Warning信息到數據庫的error log中,這時候你就知道該調整這個參數大小了。

查看當前系統mysql的error日誌 cat /var/lib/mysql/機器名.error 發現有不少waring警告。因此要調大爲20M.

根據MySQL手冊,對於2G內存的機器,推薦值是20M。

32G內存的 100M
- innodb_log_buffer_size(默認8M)

innodb_log_buffer_size=20M

innodb_log_buffer_size 這是InnoDB存儲引擎的事務日誌所使用的緩衝區。相似於Binlog Buffer,InnoDB在寫事務日誌的時候,爲了提升性能,也是先將信息寫入Innofb Log Buffer中,當知足innodb_flush_log_trx_commit參數所設置的相應條件(或者日誌緩衝區寫滿)以後,纔會將日誌寫到文件 (或者同步到磁盤)中。能夠經過innodb_log_buffer_size 參數設置其可使用的最大內存空間。

InnoDB 將日誌寫入日誌磁盤文件前的緩衝大小。理想值爲 1M 至 8M。大的日誌緩衝容許事務運行時不須要將日誌保存入磁盤而只到事務被提交(commit)。 所以,若是有大的事務處理,設置大的日誌緩衝能夠減小磁盤I/O。 在 my.cnf中以數字格式設置。

默認是8MB,系的如頻繁的系統可適當增大至4MB~8MB。固然如上面介紹所說,這個參數實際上還和另外的flush參數相關。通常來講不建議超過32MB

注:innodb_flush_log_trx_commit參數對InnoDB Log的寫入性能有很是關鍵的影響,默認值爲1。該參數能夠設置爲0,1,2,解釋以下:

0:log buffer中的數據將以每秒一次的頻率寫入到log file中,且同時會進行文件系統到磁盤的同步操做,可是每一個事務的commit並不會觸發任何log buffer 到log file的刷新或者文件系統到磁盤的刷新操做;

1:在每次事務提交的時候將log buffer 中的數據都會寫入到log file,同時也會觸發文件系統到磁盤的同步;

2:事務提交會觸發log buffer到log file的刷新,但並不會觸發磁盤文件系統到磁盤的同步。此外,每秒會有一次文件系統到磁盤同步操做。

實際測試發現,該值對插入數據的速度影響很是大,設置爲2時插入10000條記錄只須要2秒,設置爲0時只須要1秒,而設置爲1時則須要229秒。所以,MySQL手冊也建議儘可能將插入操做合併成一個事務,這樣能夠大幅提升速度。根據MySQL手冊,在存在丟失最近部分事務的危險的前提下,能夠把該值設爲0。

##  5. 集羣

MySQL官網推薦兩種集羣方式一種是InnoDB集羣還有一種是NDB集羣


### 5.1 InnoDB和NDB集羣工做方式


![](https://img2018.cnblogs.com/blog/1316204/201906/1316204-20190606155043833-1917496741.png)


### 5.2 InnoDB和NDB集羣的選擇


![](https://img2018.cnblogs.com/blog/1316204/201906/1316204-20190606151154159-279709723.png)


  NDB Cluster具備一系列獨特屬性,很是適合爲須要高可用性,快速故障轉移,高吞吐量和低延遲的應用程序提供服務。因爲其分佈式架構和多節點實現,NDB Cluster還具備特定約束,可能會使某些工做負載沒法正常運行



## 6. InnoDB鎖


不一樣的數據庫引擎使用鎖的形式截然不同,主要介紹InnoDB的鎖

### 6.1 樂觀鎖

用數據版本(Version)記錄機制實現,這是樂觀鎖最經常使用的一種實現方式。何謂數據版本?即爲數據增長一個版本標識,通常是經過爲數據庫表增長一個數字類型的 「version」 字段來實現。當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加1。當咱們提交更新的時候,判斷數據庫表對應記錄的當前版本信息與第一次取出來的version值進行比對,若是數據庫表當前版本號與第一次取出來的version值相等,則予以更新,不然認爲是過時數據。

舉例
一、數據庫表設計
三個字段,分別是id,value、version

select id,value,version from TABLE where id=#{id}

複製代碼二、每次更新表中的value字段時,爲了防止發生衝突,須要這樣操做

update TABLE
set value=2,version=version+1
where id=#{id} and version=#{version};
```

6.2 悲觀鎖

與樂觀鎖相對應的就是悲觀鎖了。悲觀鎖就是在操做數據時,認爲此操做會出現數據衝突,因此在進行每次操做時都要經過獲取鎖才能進行對相同數據的操做,這點跟java中的synchronized很類似,因此悲觀鎖須要耗費較多的時間。

  • 共享鎖

    共享鎖又稱讀鎖 read lock,是讀取操做建立的鎖。其餘用戶能夠併發讀取數據,但任何事務都不能對數據進行修改(獲取數據上的排他鎖),直到已釋放全部共享鎖。
    若是事務T對數據A加上共享鎖後,則其餘事務只能對A再加共享鎖,不能加排他鎖。得到共享鎖的事務只能讀數據,不能修改數據.

  • 排它鎖

    排他鎖 exclusive lock(也叫writer lock)又稱寫鎖。

    若事務 1 對數據對象A加上X鎖,事務 1 能夠讀A也能夠修改A,其餘事務不能再對A加任何鎖,直到事物 1 釋放A上的鎖。這保證了其餘事務在事物 1 釋放A上的鎖以前不能再讀取和修改A。排它鎖會阻塞全部的排它鎖和共享鎖

6.3 行鎖

行級鎖都是基於索引的,若是一條SQL語句用不到索引是不會使用行級鎖的,會使用表級鎖。

行級鎖的缺點是:因爲須要請求大量的鎖資源,因此速度慢,內存消耗大。

6.4 表鎖

innodb 的行鎖是在有索引的狀況下,沒有索引的表是鎖定全表的.

6.5 死鎖

死鎖(Deadlock) 
所謂死鎖:是指兩個或兩個以上的進程在執行過程當中,因爭奪資源而形成的一種互相等待的現象,若無外力做用,它們都將沒法推動下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱爲死鎖進程。因爲資源佔用是互斥的,當某個進程提出申請資源後,使得有關進程在無外力協助下,永遠分配不到必需的資源而沒法繼續運行,這就產生了一種特殊現象死鎖。

  • 產生死鎖的條件

    • 互斥條件

      一個資源每次只能被一個進程使用。

    • 請求與保持條件

      一個進程因請求資源而阻塞時,對已得到的資源保持不放。

    • 不剝奪條件

      進程已得到的資源,在末使用完以前,不能強行剝奪。

    • 循環等待條件

      若干進程之間造成一種頭尾相接的循環等待資源關係。

  • 下降死鎖的方式

    • 按同一順序訪問對象。
    • 避免事務中的用戶交互。
    • 保持事務簡短並在一個批處理中。
    • 使用低隔離級別。
    • 使用綁定鏈接。
  • 解決死鎖的方法

    • 方法1

      1.查詢是否鎖表

      show OPEN TABLES where In_use > 0;

      2.查詢進程(若是您有SUPER權限,您能夠看到全部線程。不然,您只能看到您本身的線程)

      show processlist

      3.殺死進程id(就是上面命令的id列)

      kill id
    • 方法2

      1:查看當前的事務

      SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

      2:查看當前鎖定的事務

      SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

      3:查看當前等鎖的事務

      SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

      殺死進程

      kill 進程ID

7. 事務

一個支持事務(Transaction)的數據庫,必需要具備這四種特性,不然在事務過程(Transaction processing)當中沒法保證數據的正確性,交易過程很可能達不到交易方的要求

7.1 併發問題

  • 髒讀

    (針對未提交數據)若是一個事務中對數據進行了更新,但事務尚未提交,另外一個事務能夠「看到」該事務沒有提交的更新結果,這樣形成的問題就是,若是第一個事務回滾,那麼,第二個事務在此以前所「看到」的數據就是一筆髒數據。

  • 不可重複讀

    (針對其餘提交先後,讀取數據自己的對比)不可重複讀取是指同一個事務在整個事務過程當中對同一筆數據進行讀取,每次讀取結果都不一樣。若是事務1在事務2的更新操做以前讀取一次數據,在事務2的更新操做以後再讀取同一筆數據一次,兩次結果是不一樣的,因此,Read Uncommitted也沒法避免不可重複讀取的問題。

  • 幻讀

    (針對其餘提交先後,讀取數據條數的對比) 幻讀是指一樣一筆查詢在整個事務過程當中屢次執行後,查詢所得的結果集是不同的。幻讀針對的是多筆記錄。在Read Uncommitted隔離級別下, 無論事務2的插入操做是否提交,事務1在插入操做以前和以後執行相同的查詢,取得的結果集是不一樣的,因此,Read Uncommitted一樣沒法避免幻讀的問題。

7.2 事務四大特徵(ACID)

  • 原子性(A)

    整個事務中的全部操做,要麼所有完成,要麼所有不完成,不可能停滯在中間某個環節。事務在執行過程當中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務歷來沒有執行過同樣。

  • 一致性(C)

    以轉帳案例爲例,假設有五個帳戶,每一個帳戶餘額是100元,那麼五個帳戶總額是500元,若是在這個5個帳戶之間同時發生多個轉帳,不管併發多少個,好比在A與B帳戶之間轉帳5元,在C與D帳戶之間轉帳10元,在B與E之間轉帳15元,五個帳戶總額也應該仍是500元,這就是保護性和不變性。

    • 保護性
    • 不變性
  • 隔離性/串行化(I)

    隔離狀態執行事務,使它們好像是系統在給定時間內執行的惟一操做。若是有兩個事務,運行在相同的時間內,執行相同的功能,事務的隔離性將確保每一事務在系統中認爲只有該事務在使用系統。這種屬性有時稱爲串行化,爲了防止事務操做間的混淆,必須串行化或序列化請求,使得在同一時間僅有一個請求用於同一數據。

    • read uncommitted
    - 事物A和事物B,事物A未提交的數據,事物B能夠讀取到
    - 這裏讀取到的數據叫作「髒數據」
    - 這種隔離級別最低,這種級別通常是在理論上存在,數據庫隔離級別通常都高於該級別
    • read committed

      • 事物A和事物B,事物A提交的數據,事物B才能讀取到
      • 這種隔離級別高於讀未提交
      • 換句話說,對方事物提交以後的數據,我當前事物才能讀取到
      • 這種級別能夠避免「髒數據」
      • 這種隔離級別會致使「不可重複讀取」
      • Oracle默認隔離級別
    • repeatable read

      在可重複讀中,該sql第一次讀取到數據後,就將這些數據加鎖(悲觀鎖),其它事務沒法修改這些數據,就能夠實現可重複讀了。但這種方法卻沒法鎖住insert的數據,因此當事務A先前讀取了數據,或者修改了所有數據,事務B仍是能夠insert數據提交,這時事務A就會發現莫名其妙多了一條以前沒有的數據,這就是幻讀,不能經過行鎖來避免。須要Serializable隔離級別 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這麼作能夠有效的避免幻讀、不可重複讀、髒讀等問題,但會極大的下降數據庫的併發能力。

    • serializable

      • 事務A和事務B,事務A在操做數據庫時,事務B只能排隊等待
      • 這種隔離級別不多使用,吞吐量過低,用戶體驗差
      • 這種級別能夠避免「幻像讀」,每一次讀取的都是數據庫中真實存在數據,事務A與事務B串行,而不併發
  • 持久性(D)

    在事務完成之後,該事務對數據庫所做的更改便持久的保存在數據庫之中,並不會被回滾。

mysql參數調優參考: 參數配置

相關文章
相關標籤/搜索