久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      MySQL之鎖和事務(wù)隔離級(jí)別(介紹)

      如今的互聯(lián)網(wǎng),開發(fā)一個(gè)大型的多人APP,你一定離不開數(shù)據(jù)庫(kù)。而如何保證所有人能夠高并發(fā)的進(jìn)行讀寫一直是一個(gè)高難度的架構(gòu)問(wèn)題,先刨去高并發(fā),保證一致性讀寫這個(gè)問(wèn)題最常用的手段是事務(wù),而實(shí)現(xiàn)一個(gè)事務(wù)的關(guān)鍵點(diǎn)在于鎖機(jī)制。

      MySQL之鎖和事務(wù)隔離級(jí)別(介紹)

      今天我們就來(lái)介紹下InnoDB存儲(chǔ)引擎如何在高并發(fā)下實(shí)現(xiàn)鎖機(jī)制來(lái)滿足一致性讀寫的原理和實(shí)現(xiàn)。

      數(shù)據(jù)庫(kù)的鎖機(jī)制是區(qū)別于文件系統(tǒng)的一個(gè)關(guān)鍵特性。用于管理對(duì)共享資源的并發(fā)訪問(wèn)。InnoDB會(huì)在很多地方使用鎖機(jī)制,比如操作緩沖池中的數(shù)據(jù)表、LRU頁(yè)列表、數(shù)據(jù)行,為了保證一致性和完整性,需要有鎖的機(jī)制。

      對(duì)于不同數(shù)據(jù)庫(kù),鎖機(jī)制的設(shè)計(jì)和實(shí)現(xiàn)完全不同:

      • MyISAM引擎: 表鎖設(shè)計(jì),并發(fā)讀沒(méi)有問(wèn)題,并發(fā)寫性能差。
      • Microsoft SQL Server: 支持樂(lè)觀并發(fā)和悲觀并發(fā),樂(lè)觀并發(fā)下支持行級(jí)鎖,維持鎖的開銷大,在行鎖數(shù)量超過(guò)閾值后會(huì)升級(jí)為表鎖。
      • InnoDB引擎: 支持行鎖,提供一致性的非鎖定讀。行鎖沒(méi)有額外開銷,性能不會(huì)下降。
      • Oracle:和InnoDB引擎非常類似。

      兩類鎖:lock和latch

      數(shù)據(jù)庫(kù)中l(wèi)ock和latch都可以稱為鎖,但是有很大的區(qū)別。

      latch一般稱為閂鎖,用于保證并發(fā)線程操作臨界資源的正確性,作用對(duì)象是內(nèi)存數(shù)據(jù)結(jié)構(gòu),要求鎖定時(shí)間非常短,不會(huì)檢測(cè)死鎖。在InnoDB引擎中又分為mutex(互斥量)和rwlock(讀寫鎖)。

      lock是用來(lái)鎖定數(shù)據(jù)庫(kù)中的對(duì)象,如表、頁(yè)、行,作用對(duì)象是事務(wù),在commit/rollback后釋放,會(huì)檢測(cè)死鎖。分為行鎖、表鎖、意向鎖。

      我們下面的鎖指的都是lock類鎖。

      四種鎖類型

      InnoDB支持四種鎖:

      • 共享鎖(S Lock):允許事務(wù)讀一行數(shù)據(jù)
      • 排他鎖(X Lock):允許事務(wù)刪除或更新一行數(shù)據(jù)
      • 意向共享鎖(Intention S Lock):事務(wù)想要獲得一張表中某幾行的共享鎖
      • 意向排他鎖(Intention X Lock):事務(wù)想要獲得一張表中某幾行的排他鎖

      當(dāng)事務(wù)T1獲取了行r的共享鎖,由于讀取不會(huì)改變行數(shù)據(jù),因此事務(wù)T2也可以直接獲得行r的共享鎖,此時(shí)稱為鎖兼容(Lock Compatible)。

      而當(dāng)事務(wù)T3想要獲取行r的排他鎖進(jìn)行修改數(shù)據(jù)時(shí),就需要等待T1/T2釋放行共享鎖,此時(shí)稱為鎖不兼容。

      S鎖和X鎖都是行鎖,而IS鎖和IX鎖都為意向鎖,屬于表鎖。意向鎖的設(shè)計(jì)是為了在一個(gè)事務(wù)中揭示下一行將被請(qǐng)求的鎖類型,即在表鎖的更細(xì)粒度進(jìn)行鎖定。由于InnoDB支持表鎖,因此意向鎖不會(huì)阻塞除全表掃描外的任何請(qǐng)求。

      鎖的兼容性:

      IS IX S X
      IS 兼容 兼容 兼容 不兼容
      IX 兼容 兼容 不兼容 不兼容
      S 兼容 不兼容 兼容 不兼容
      X 不兼容 不兼容 不兼容 不兼容

      存儲(chǔ)事務(wù)和鎖信息的三張表

      我們可以通過(guò)show engine innodb status命令在事務(wù)部分查看當(dāng)前鎖請(qǐng)求的信息。

      從InnoDB1.0開始,在INFORMATION_SCHEMA架構(gòu)下添加了INNODB_TRX(transaction事務(wù)表)、INNODB_LOCKS(鎖表)、INNODB_LOCK_WAITS(鎖等待表),通過(guò)這三張表,可以讓我們實(shí)時(shí)監(jiān)控當(dāng)前事務(wù)并分析可能存在的表問(wèn)題。

      三個(gè)表的定義分別為:

      INNODB_TRX
      trx_id InnoDB存儲(chǔ)引擎內(nèi)部唯一的事務(wù)ID
      trx_state 當(dāng)前事務(wù)的狀態(tài)
      trx_started 事務(wù)的開始時(shí)間
      trx_requested_lock_id 等待事務(wù)的鎖IDC,當(dāng)狀態(tài)不為L(zhǎng)OCK WAIT時(shí)為NULL
      trx_wait_started 事務(wù)等待開始的時(shí)間
      trx_weight 事務(wù)的權(quán)重,反映一個(gè)事務(wù)修改和鎖定的行數(shù)。當(dāng)需要回滾時(shí),選擇該值最小的事務(wù)進(jìn)行回滾
      trx_mysql_thread_id MySQL的線程ID,show processlist顯示的結(jié)果
      trx_query 事務(wù)運(yùn)行的SQL語(yǔ)句
      INNODB_LOCKS
      lock_id 鎖ID
      lock_trx_id 事務(wù)ID
      lock_mode 鎖的模式
      lock_type 鎖的類型,表鎖或行鎖
      lock_table 要加鎖的表
      lock_index 鎖住的索引
      lock_space 鎖對(duì)象的space id
      lock_page 事務(wù)鎖定頁(yè)的數(shù)量,表鎖時(shí)為NULL
      lock_rec 事務(wù)鎖定行的數(shù)量,表鎖時(shí)為NULL
      lock_data 事務(wù)鎖定記錄的主鍵值,表鎖時(shí)為NULL
      INNODB_LOCK_WAITS
      requesting_trx_id 申請(qǐng)鎖資源的事務(wù)ID
      requesting_lock_id 申請(qǐng)的鎖的ID
      blocking_trx_id 阻塞的事務(wù)ID
      blocking_lock_id 阻塞的鎖的ID

      通過(guò)INNODB_TRX我們可以看到所有的事務(wù),以及事務(wù)是否被阻塞,阻塞的鎖ID是什么。
      之后,通過(guò)INNODB_LOCKS查看所有的鎖信息。
      之后,通過(guò)INNODB_LOCK_WAITS可以查看到鎖的等待信息以及阻塞關(guān)系。

      通過(guò)這三種表能夠較為清晰的查看事務(wù)和鎖的情況,也可以聯(lián)合查詢,在下面的一些場(chǎng)景下我們會(huì)來(lái)展示這三個(gè)表的內(nèi)容。

      隔離級(jí)別

      首先我們來(lái)說(shuō)下數(shù)據(jù)庫(kù)的四種事務(wù)隔離級(jí)別:

      • READ UNCOMMITTED(0): 瀏覽訪問(wèn)級(jí)別,存在臟讀、不可重復(fù)讀、幻讀
      • READ COMMITTED(1): 游標(biāo)穩(wěn)定級(jí)別,存在不可重復(fù)度、幻讀
      • REPEATABLE READ(2): 存在幻讀
      • SERIALIZABLE(3): 隔離級(jí)別,保證事務(wù)安全,但完全串行,性能低

      這四種事務(wù)隔離級(jí)別是指定的SQL標(biāo)準(zhǔn),InnoDB默認(rèn)的隔離級(jí)別是REAPEATABLE READ,但與其他數(shù)據(jù)庫(kù)不同的時(shí),它同時(shí)使用了Next-Key-Lock鎖的算法,能夠避免幻讀的產(chǎn)生,因此能夠完全滿足事務(wù)的隔離性要求,即達(dá)到SERIALIZABLE隔離級(jí)別。

      隔離級(jí)別越低,事務(wù)請(qǐng)求的鎖越少或持鎖時(shí)間越短,因此大部分?jǐn)?shù)據(jù)庫(kù)的默認(rèn)隔離級(jí)別為READ COMMITED。但是有相關(guān)的分析也指出,隔離級(jí)別的性能開銷幾乎一樣,因此用戶無(wú)須通過(guò)調(diào)整隔離級(jí)別來(lái)提高性能。

      查看和修改事務(wù)隔離級(jí)別的命令:

      mysql> select @@session.tx_isolation; +------------------------+ | @@session.tx_isolation | +------------------------+ | REPEATABLE-READ        | +------------------------+ 1 row in set (0.00 sec)  mysql> set session transaction isolation level SERIALIZABLE; Query OK, 0 rows affected (0.00 sec)

      示例中修改了本次會(huì)話的事務(wù)隔離級(jí)別,如果需要修改全局參數(shù),可以替換session為global。如果想要永久修改,需要修改配置文件:

      [mysqld] transaction-isolation = READ-COMMITED

      在SERIALIZABLE的事務(wù)隔離級(jí)別,InnoDB會(huì)對(duì)每個(gè)SELECT語(yǔ)句后自動(dòng)加上LOCK IN SHARE MODE,來(lái)對(duì)讀操作加上一個(gè)共享鎖,因此不再支持一致性的非鎖定讀。

      由于InnoDB在REPEATABLE READ隔離級(jí)別就可以達(dá)到SERIALIZABLE,因此一般不用使用最高隔離級(jí)別。

      一致性非鎖定讀和多版本并發(fā)控制

      一致性非鎖定讀(consistent nonlocking read)是指InnoDB通過(guò)行多版本控制(Multi Version Concurrency Control, MVCC)的方法來(lái)讀取當(dāng)前執(zhí)行時(shí)間數(shù)據(jù)庫(kù)中行的數(shù)據(jù)。

      即如果讀取的行正在執(zhí)行變更操作,這時(shí)讀取不會(huì)等待行鎖的釋放,而是會(huì)讀取行的一個(gè)快照數(shù)據(jù)。快照是指該行的一個(gè)歷史數(shù)據(jù),通過(guò)undo操作來(lái)完成。這種方式極大提高了數(shù)據(jù)庫(kù)的并發(fā)性,這也是InnoDB的默認(rèn)設(shè)置。

      快照是當(dāng)前行的一個(gè)歷史版本,但可能存在多個(gè)版本,行數(shù)據(jù)存在多個(gè)快照數(shù)據(jù),這種技術(shù)成為行多版本技術(shù),由此帶來(lái)的并發(fā)控制,稱為多版本并發(fā)控制(MVCC)。InnoDB在READ COMMITED 和 REPEATABLE READ隔離級(jí)別時(shí),會(huì)使用非鎖定的一致性讀,但是在這兩種隔離級(jí)別使用的快找數(shù)據(jù)定義卻不同:

      • READ COMMITED: 總是讀取最新一份快照
      • REPEATABLE READ: 總是讀取事務(wù)開始時(shí)的行數(shù)據(jù)版本

      我們執(zhí)行一個(gè)示例:

      一致性非鎖定讀
      時(shí)間 會(huì)話A 會(huì)話B
      1 BEGIN
      2 select * from z where a = 3;
      3 BEGIN
      4 update z set b=2 where a=3;
      5 select * from z where a = 3;
      6 COMMIT;
      7 select * from z where a = 3;
      8 COMMIT;

      在這個(gè)例子中我們可以清晰的看到0、1、2三種隔離級(jí)別的區(qū)別:

      #在事務(wù)開始前我們可以分別調(diào)整為0、1、2三種隔離級(jí)別,來(lái)查看不同的輸出 mysql> set session transaction isolation level READ UNCOMMITTED; Query OK, 0 rows affected (0.00 sec)  mysql> select @@tx_isolation; +------------------+ | @@tx_isolation   | +------------------+ | READ-UNCOMMITTED | +------------------+ 1 row in set (0.00 sec)  # A會(huì)話:T1事務(wù) mysql> begin; Query OK, 0 rows affected (0.00 sec)  mysql> select * from z where a = 3; +---+------+ | a | b    | +---+------+ | 3 |    1 | +---+------+ 1 row in set (0.00 sec)  # B會(huì)話:T2事務(wù) mysql> begin; Query OK, 0 rows affected (0.00 sec)  mysql> update z set b=2 where a=3; Query OK, 1 row affected (0.00 sec) Rows matched: 1  Changed: 1  Warnings: 0  # A會(huì)話:T1事務(wù),如果此時(shí)隔離級(jí)別是READ-UNCOMMITTED,因?yàn)榇丝淌聞?wù)2可能會(huì)回滾,所以出現(xiàn)了臟讀 mysql> select * from z where a=3; +---+------+ | a | b    | +---+------+ | 3 |    2 | +---+------+ 1 row in set (0.00 sec)  # A會(huì)話:T1事務(wù),如果此時(shí)隔離級(jí)別是大于READ-UNCOMMITTED的更高級(jí)別 mysql> select * from z where a=3; +---+------+ | a | b    | +---+------+ | 3 |    1 | +---+------+ 1 row in set (0.00 sec)  # B會(huì)話:T2事務(wù) mysql> commit; Query OK, 0 rows affected (0.00 sec)  # A會(huì)話:T1事務(wù),如果此時(shí)隔離級(jí)別是READ-COMMITTED,因?yàn)閿?shù)據(jù)和事務(wù)開始時(shí)讀取的出現(xiàn)了不一致,因此稱為不可重復(fù)讀,能夠讀到其他事務(wù)的結(jié)果,違反了事務(wù)的隔離性 mysql> select * from z where a=3; +---+------+ | a | b    | +---+------+ | 3 |    2 | +---+------+ 1 row in set (0.00 sec)  # A會(huì)話:T1事務(wù),如果此時(shí)隔離級(jí)別是大于READ-COMMITTED的更高級(jí)別 mysql> select * from z where a=3; +---+------+ | a | b    | +---+------+ | 3 |    1 | +---+------+ 1 row in set (0.00 sec)  # A會(huì)話:T1事務(wù) mysql> commit; Query OK, 0 rows affected (0.00 sec)

      一致性鎖定讀和SERIALIZABLE隔離

      在默認(rèn)的REPEATABLE READ隔離級(jí)別時(shí),InnoDB使用的是一致性非鎖定讀。但有時(shí)我們也需要顯示的指定使用一致性鎖定讀來(lái)保證讀取操作時(shí)對(duì)數(shù)據(jù)進(jìn)行加鎖達(dá)到一致性。這要求數(shù)據(jù)庫(kù)支持鎖定讀加鎖語(yǔ)句:

      • select … for update: 讀取時(shí)對(duì)行記錄加X(jué)鎖
      • select … lock in share mode:讀取時(shí)對(duì)行記錄加一個(gè)S鎖

      這兩種鎖必須在一個(gè)事務(wù)中,當(dāng)事務(wù)提交后鎖也就釋放了,因此務(wù)必加上BEGIN, START TRANSACTION或者SET AUTOCOMMIT=0。

      我們?cè)谇懊娓綦x級(jí)別時(shí)也說(shuō)過(guò)SERIALIZABLE隔離級(jí)別會(huì)對(duì)讀操作自動(dòng)加上LOCK IN SHARE MODE指令來(lái)加上一個(gè)共享鎖,因此不再支持一致性的非鎖定讀。這也是隔離級(jí)別3的一大特性。

      總結(jié)

      由于鎖的概念非常重要,這里先講了鎖的概念、鎖的類型、鎖的信息查看、事務(wù)的隔離級(jí)別和區(qū)別,后面我們會(huì)繼續(xù)說(shuō)鎖的算法、鎖的三種問(wèn)題和幻讀、死鎖和鎖升級(jí)。

      推薦學(xué)習(xí):MySQL教程

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)