亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

  • 站長資訊網(wǎng)
    最全最豐富的資訊網(wǎng)站

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

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

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

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

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

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

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

    兩類鎖:lock和latch

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

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

    lock是用來鎖定數(shù)據(jù)庫中的對(duì)象,如表、頁、行,作用對(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ù)和鎖信息的三張表

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

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

    三個(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)不為LOCK 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語句
    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ù)鎖定頁的數(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

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

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

    隔離級(jí)別

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

    • READ UNCOMMITTED(0): 瀏覽訪問級(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ù)庫不同的時(shí),它同時(shí)使用了Next-Key-Lock鎖的算法,能夠避免幻讀的產(chǎn)生,因此能夠完全滿足事務(wù)的隔離性要求,即達(dá)到SERIALIZABLE隔離級(jí)別。

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

    查看和修改事務(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語句后自動(dòng)加上LOCK IN SHARE MODE,來對(duì)讀操作加上一個(gè)共享鎖,因此不再支持一致性的非鎖定讀。

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

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

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

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

    快照是當(dāng)前行的一個(gè)歷史版本,但可能存在多個(gè)版本,行數(shù)據(jù)存在多個(gè)快照數(shù)據(jù),這種技術(shù)成為行多版本技術(shù),由此帶來的并發(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í)別,來查看不同的輸出 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í)我們也需要顯示的指定使用一致性鎖定讀來保證讀取操作時(shí)對(duì)數(shù)據(jù)進(jìn)行加鎖達(dá)到一致性。這要求數(shù)據(jù)庫支持鎖定讀加鎖語句:

    • select … for update: 讀取時(shí)對(duì)行記錄加X鎖
    • 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í)也說過SERIALIZABLE隔離級(jí)別會(huì)對(duì)讀操作自動(dòng)加上LOCK IN SHARE MODE指令來加上一個(gè)共享鎖,因此不再支持一致性的非鎖定讀。這也是隔離級(jí)別3的一大特性。

    總結(jié)

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

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

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