MySQL 面試之必會知識點(diǎn)

Mysql

事務(wù)

特征:

  1. 原子性:不可分割的操作單元,事務(wù)中所有操作,要么全部成功撞蚕;要么撤回到執(zhí)行事務(wù)之前的狀態(tài)
  2. 一致性:如果在執(zhí)行事務(wù)之前數(shù)據(jù)庫是一致的,那么在執(zhí)行事務(wù)之后數(shù)據(jù)庫也還是一致的过牙;
  3. 隔離性:事務(wù)操作之間彼此獨(dú)立和透明互不影響诈豌。事務(wù)獨(dú)立運(yùn)行。這通常使用鎖來實(shí)現(xiàn)抒和。一個(gè)事務(wù)處理后的結(jié)果矫渔,影響了其他事務(wù),那么其他事務(wù)會撤回摧莽。事務(wù)的100%隔離庙洼,需要犧牲速度。
  4. 持久性:事務(wù)一旦提交镊辕,其結(jié)果就是永久的油够。即便發(fā)生系統(tǒng)故障,也能恢復(fù)征懈。

存儲引擎 MyISAM和InnoDB區(qū)別:

  1. MyISAM不支持外鍵和事務(wù)石咬,innodb支持

  2. MyISAM鎖的粒度是表級,而InnoDB支持行級鎖定

  3. MyISAM支持全文類型索引卖哎,而InnoDB不支持全文索引鬼悠。

  4. MyISAM相對簡單,所以在效率上要優(yōu)于InnoDB亏娜,小型應(yīng)用可以考慮使用MyISAM

  5. Myisam創(chuàng)建表生成三個(gè)文件:.frm數(shù)據(jù)表結(jié)構(gòu) .myd數(shù)據(jù)文件 .myi索引文件焕窝,Innodb只生成一個(gè)frm文件,數(shù)據(jù)存放在ibdata1.log

  6. MyisAM使用delete語句刪除后并不會立刻清理磁盤空間维贺,需要定時(shí)清理它掂,命令:OPTIMIZE table dept;


    應(yīng)用場景

    • MyISAM管理非事務(wù)表。它提供高速存儲和檢索溯泣,以及全文搜索能力虐秋。如果應(yīng)用中需要執(zhí)行大量的SELECT查詢,那么MyISAM是更好的選擇垃沦。
    • InnoDB用于事務(wù)處理應(yīng)用程序客给,具有眾多特性,包括ACID事務(wù)支持栏尚。如果應(yīng)用中需要執(zhí)行大量的INSERT或UPDATE操作起愈,則應(yīng)該使用InnoDB只恨,這樣可以提高多用戶并發(fā)操作的性能。

delete drop truncate區(qū)別

  • truncate 和 delete只刪除數(shù)據(jù)抬虽,不刪除表結(jié)構(gòu) ,drop刪除表結(jié)構(gòu)官觅,并且釋放所占的空間。
  • 刪除數(shù)據(jù)的速度阐污,一般來說: drop> truncate > delete
  • delete屬于DML語言休涤,需要事務(wù)管理,commit之后才能生效笛辟。drop和truncate屬于DDL語言功氨,操作立刻生效,不可回滾
  • 使用場合:
    • 當(dāng)你不再需要該表時(shí)手幢, 用 drop;
    • 當(dāng)你仍要保留該表捷凄,但要?jiǎng)h除所有記錄時(shí), 用 truncate;
    • 當(dāng)你要?jiǎng)h除部分記錄時(shí)(always with a where clause), 用 delete.

注意: 對于有主外鍵關(guān)系的表围来,不能使用truncate而應(yīng)該使用不帶where子句的delete語句跺涤,由于truncate不記錄在日志中,不能夠激活觸發(fā)器

索引

MyISAM引擎使用B+Tree作為索引結(jié)構(gòu)监透,葉節(jié)點(diǎn)的data域存放的是數(shù)據(jù)記錄的地址桶错。因此,MyISAM中索引檢索的算法為首先按照B+Tree搜索算法搜索索引胀蛮,如果指定的Key存在院刁,則取出其data域的值,然后以data域的值為地址粪狼,讀取相應(yīng)數(shù)據(jù)記錄退腥。

img

InnoDB也使用B+Tree作為索引結(jié)構(gòu)InnoDB的數(shù)據(jù)文件本身就是索引文件鸳玩。MyISAM索引文件和數(shù)據(jù)文件是分離的阅虫,索引文件僅保存數(shù)據(jù)記錄的地址(這一點(diǎn)可以通過在data目錄下查看數(shù)據(jù)庫文件驗(yàn)證。Innodb每一個(gè)數(shù)據(jù)庫只有一個(gè)數(shù)據(jù)文件不跟,而Myisam則有三個(gè)(數(shù)據(jù)文件、索引文件米碰、表結(jié)構(gòu)文件))窝革。而在InnoDB中,表數(shù)據(jù)文件本身就是按B+Tree組織的一個(gè)索引結(jié)構(gòu)吕座,這棵樹的葉節(jié)點(diǎn)data域保存了完整的數(shù)據(jù)記錄虐译。這個(gè)索引的key是數(shù)據(jù)表的主鍵,因此InnoDB表數(shù)據(jù)文件本身就是主索引吴趴。

img

上圖是InnoDB主索引(同時(shí)也是數(shù)據(jù)文件)的示意圖漆诽,可以看到葉節(jié)點(diǎn)包含了完整的數(shù)據(jù)記錄。這種索引叫做聚集索引。因?yàn)镮nnoDB的數(shù)據(jù)文件本身要按主鍵聚集厢拭,所以InnoDB要求表必須有主鍵(MyISAM可以沒有)兰英,如果沒有顯式指定,則MySQL系統(tǒng)會自動選擇一個(gè)可以唯一標(biāo)識數(shù)據(jù)記錄的列作為主鍵供鸠,如果不存在這種列畦贸,則MySQL自動為InnoDB表生成一個(gè)隱含字段作為主鍵,這個(gè)字段長度為6個(gè)字節(jié)楞捂,類型為長整形

第二個(gè)與MyISAM索引的不同是InnoDB的輔助索引(非主鍵索引)data域存儲相應(yīng)記錄主鍵的值而不是地址薄坏。換句話說,InnoDB的所有輔助索引都引用主鍵作為data域寨闹。例如胶坠,圖11為定義在Col3上的一個(gè)輔助索引:這里以英文字符的ASCII碼作為比較準(zhǔn)則。聚集索引這種實(shí)現(xiàn)方式使得按主鍵的搜索十分高效繁堡,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵涵但,然后用主鍵到主索引中檢索獲得記錄。了解不同存儲引擎的索引實(shí)現(xiàn)方式對于正確使用和優(yōu)化索引都非常有幫助帖蔓,例如知道了InnoDB的索引實(shí)現(xiàn)后矮瘟,就很容易明白為什么不建議使用過長的字段作為主鍵因?yàn)樗休o助索引都引用主索引塑娇,過長的主索引會令輔助索引變得過大澈侠。再例如,用非單調(diào)的字段作為主鍵在InnoDB中不是個(gè)好主意埋酬,因?yàn)镮nnoDB數(shù)據(jù)文件本身是一顆B+Tree哨啃,非單調(diào)的主鍵會造成在插入新記錄時(shí)數(shù)據(jù)文件為了維持B+Tree的特性而頻繁的分裂調(diào)整,十分低效写妥,而使用自增字段作為主鍵則是一個(gè)很好的選擇拳球。

img

基于B+樹

B樹的定義:有序數(shù)組+平衡多叉樹

多叉排序樹

通常會定義一個(gè)最小度:t>=2(等于1的時(shí)候退化成為二叉搜索樹):

  • 每個(gè)節(jié)點(diǎn)最多含有(2t-1)個(gè)關(guān)鍵字,每個(gè)節(jié)點(diǎn)最多有2t的孩子節(jié)點(diǎn)珍特。
  • 當(dāng)節(jié)點(diǎn)的關(guān)鍵字個(gè)數(shù)為2t-1的時(shí)候祝峻,稱該節(jié)點(diǎn)已滿,需要分裂扎筒。分裂從中間節(jié)點(diǎn)一分為二莱找,中間結(jié)點(diǎn)被提升到父節(jié)點(diǎn),如果父節(jié)點(diǎn)也滿嗜桌,則父節(jié)點(diǎn)接著分裂奥溺,直到根節(jié)點(diǎn)。
  • 查找可以在非葉子節(jié)點(diǎn)完成骨宠,一個(gè)鍵值只會出現(xiàn)一次浮定,而B+樹的鍵一定出現(xiàn)在葉子節(jié)點(diǎn)相满,并且可能在非葉子節(jié)點(diǎn)重復(fù)出現(xiàn),以維持平衡桦卒。

B+樹是一種變種的B-樹立美。有序數(shù)組鏈表+平衡多叉樹

基本和B樹類似,只有葉子節(jié)點(diǎn)存放數(shù)據(jù)闸盔,而且葉子節(jié)點(diǎn)之間通過指針相連悯辙。

B+-tree的磁盤讀寫代價(jià)更低:B+-tree的內(nèi)部結(jié)點(diǎn)并沒有指向關(guān)鍵字具體信息的指針嘀掸。因此內(nèi)部結(jié)點(diǎn)相對B 樹更小

B+-tree的查詢效率更加穩(wěn)定:由于非終結(jié)點(diǎn)并不是最終指向文件內(nèi)容的結(jié)點(diǎn)喷楣,而只是葉子結(jié)點(diǎn)中關(guān)鍵字的索引。所以任何關(guān)鍵字的查找必須走一條從根結(jié)點(diǎn)到葉子結(jié)點(diǎn)的路弧圆。所有關(guān)鍵字查詢的路徑長度相同击费,導(dǎo)致每一個(gè)數(shù)據(jù)的查詢效率相當(dāng)拢蛋。

索引種類

  1. 主鍵索引(把某列設(shè)為主鍵,則該列就是索引蔫巩,主鍵不能重復(fù))
  2. 唯一索引(unique)谆棱,該列具有唯一性,同時(shí)又是索引
  3. index 普通索引
  4. 全文索引 (fulltext) 只有MyISAM存儲引擎支持 (注:mysql 5.6之后圆仔,Innodb也開始支持全文索引垃瞧,mysql5.6較之前版本有較大更新,有興趣的小伙伴可以去查一查)

適合加索引的列:

  1. 經(jīng)常查詢的列上加索引

  2. 唯一性太差的列不要加索引(重復(fù)太多)坪郭,相反唯一性比較好的列適合加索引

  3. 不經(jīng)常修改的列適合加个从。經(jīng)常修改的列不要加索引(列修改,索引也要改)

    因?yàn)樗饕膭?chuàng)建和更改是有開銷的歪沃。

索引生效條件

假設(shè)index(a,b,c)

  1. 最左前綴匹配:模糊查詢時(shí)嗦锐,使用%匹配時(shí):’a%‘會使用索引,’%a‘不會使用索引
  2. 條件中有or沪曙,索引不會生效
  3. a and c奕污,a生效,c不生效
  4. b and c液走,都不生效
  5. a and b > 5 and c,a和b生效碳默,c不生效。

創(chuàng)建 刪除 查看

  1. 創(chuàng)建方法一:

    create [unique | fulltext] index 索引名 on 表名(列名)

  2. 創(chuàng)建方法二:

普通索引:alter table 表名 add index 索引名 (列名)
主鍵索引:alter table 表名 add primary key (列名)
唯一索引:alter table 表明 add unique (列名)

?

  1. 刪除

    drop index 索引名 on 表名育灸;
    
    alter table 表名 drop index 索引名
    
    alter table 表明 drop primary key
    

    ?

  2. 查看

show index from 表名腻窒;

?

檢測索引的效果

show status like '%handler_read%'越大越好

sql語句分類:

  1. DDL:數(shù)據(jù)定義語言(create alter drop)
  2. DML:數(shù)據(jù)操作語句(insert update delete)
    1. select 數(shù)據(jù)查詢語句
  3. DTL:數(shù)據(jù)事務(wù)語句(commit collback savapoint)
  4. DCL:數(shù)據(jù)控制語句(grant revoke)

mysql優(yōu)化:

  1. 數(shù)據(jù)表的優(yōu)化(符合3范式)
    1. 1范式:1NF是對屬性的原子性約束,要求屬性具有原子性磅崭,不可再分解;(只要是關(guān)系型數(shù)據(jù)庫都滿足1NF)
    2. 2范式:2NF是對記錄的惟一性約束瓦哎,要求記錄有惟一標(biāo)識砸喻,即實(shí)體的惟一性柔逼;
    3. 3范式:3NF是對字段冗余性的約束,即任何字段不能由其他字段派生出來割岛,它要求字段沒有冗余愉适。沒有冗余的數(shù)據(jù)庫設(shè)計(jì)可以做到
    4. 但是,沒有冗余的數(shù)據(jù)庫未必是最好的數(shù)據(jù)庫癣漆,有時(shí)為了提高運(yùn)行效率维咸,就必須降低范式標(biāo)準(zhǔn),適當(dāng)保留冗余數(shù)據(jù)惠爽。具體做法是:在概念數(shù)據(jù)模型設(shè)計(jì)時(shí)遵守第三范式癌蓖,降低范式標(biāo)準(zhǔn)的工作放到物理數(shù)據(jù)模型設(shè)計(jì)時(shí)考慮。降低范式就是增加字段婚肆,允許冗余租副。
  2. sql語句優(yōu)化 索引
  3. 使用order by null禁用排序。group by 默認(rèn)情況下會排序(file sorting)较性,非常費(fèi)時(shí)用僧。
  4. 使用join代替子查詢(子查詢會默認(rèn)創(chuàng)建臨時(shí)表)
  5. 分表:
    1. 垂直分割:將字段分開
    2. 水平分割:將記錄分開
  6. 讀寫分離

Innodb中的事務(wù)隔離級別和鎖的關(guān)系

前言:

我們都知道事務(wù)的幾種性質(zhì),數(shù)據(jù)庫為了維護(hù)這些性質(zhì)赞咙,尤其是一致性和隔離性责循,一般使用加鎖這種方式。同時(shí)數(shù)據(jù)庫又是個(gè)高并發(fā)的應(yīng)用攀操,同一時(shí)間會有大量的并發(fā)訪問院仿,如果加鎖過度,會極大的降低并發(fā)處理能力崔赌。所以對于加鎖的處理意蛀,可以說就是數(shù)據(jù)庫對于事務(wù)處理的精髓所在。這里通過分析MySQL中InnoDB引擎的加鎖機(jī)制健芭,來拋磚引玉县钥,讓讀者更好的理解,在事務(wù)處理中數(shù)據(jù)庫到底做了什么慈迈。

一次封鎖or兩段鎖若贮?

因?yàn)橛写罅康牟l(fā)訪問,為了預(yù)防死鎖痒留,一般應(yīng)用中推薦使用一次封鎖法谴麦,就是在方法的開始階段,已經(jīng)預(yù)先知道會用到哪些數(shù)據(jù)伸头,然后全部鎖住匾效,在方法運(yùn)行之后,再全部解鎖恤磷。這種方式可以有效的避免循環(huán)死鎖面哼,但在數(shù)據(jù)庫中卻不適用野宜,因?yàn)樵谑聞?wù)開始階段,數(shù)據(jù)庫并不知道會用到哪些數(shù)據(jù)魔策。
數(shù)據(jù)庫遵循的是兩段鎖協(xié)議匈子,將事務(wù)分成兩個(gè)階段,加鎖階段和解鎖階段(所以叫兩段鎖)

  • 加鎖階段:在該階段可以進(jìn)行加鎖操作闯袒。在對任何數(shù)據(jù)進(jìn)行讀操作之前要申請并獲得S鎖(共享鎖虎敦,其它事務(wù)可以繼續(xù)加共享鎖,但不能加排它鎖)政敢,在進(jìn)行寫操作之前要申請并獲得X鎖(排它鎖其徙,其它事務(wù)不能再獲得任何鎖)。加鎖不成功堕仔,則事務(wù)進(jìn)入等待狀態(tài)擂橘,直到加鎖成功才繼續(xù)執(zhí)行。
  • 解鎖階段:當(dāng)事務(wù)釋放了一個(gè)封鎖以后摩骨,事務(wù)進(jìn)入解鎖階段通贞,在該階段只能進(jìn)行解鎖操作不能再進(jìn)行加鎖操作。
事務(wù) 加鎖/解鎖處理
begin恼五;
insert into test ..... 加insert對應(yīng)的鎖
update test set... 加update對應(yīng)的鎖
delete from test .... 加delete對應(yīng)的鎖
commit; 事務(wù)提交時(shí)昌罩,同時(shí)釋放insert、update灾馒、delete對應(yīng)的鎖

這種方式雖然無法避免死鎖茎用,但是兩段鎖協(xié)議可以保證事務(wù)的并發(fā)調(diào)度是串行化(串行化很重要,尤其是在數(shù)據(jù)恢復(fù)和備份的時(shí)候)的睬罗。

事務(wù)中的加鎖方式

事務(wù)的四種隔離級別

在數(shù)據(jù)庫操作中轨功,為了有效保證并發(fā)讀取數(shù)據(jù)的正確性,提出的事務(wù)隔離級別容达。我們的數(shù)據(jù)庫鎖古涧,也是為了構(gòu)建這些隔離級別存在的。

隔離級別 臟讀(Dirty Read) 不可重復(fù)讀(NonRepeatable Read) 幻讀(Phantom Read)
未提交讀(Read uncommitted) 可能 可能 可能
已提交讀(Read committed) 不可能 可能 可能
可重復(fù)讀(Repeatable read) 不可能 不可能 可能
可串行化(Serializable ) 不可能 不可能 不可能
  • 未提交讀(Read Uncommitted):允許臟讀花盐,也就是可能讀取到其他會話中未提交事務(wù)修改的數(shù)據(jù)
  • 提交讀(Read Committed):只能讀取到已經(jīng)提交的數(shù)據(jù)羡滑。Oracle等多數(shù)數(shù)據(jù)庫默認(rèn)都是該級別 (不重復(fù)讀)
  • 可重復(fù)讀(Repeated Read):可重復(fù)讀。在同一個(gè)事務(wù)內(nèi)的查詢都是事務(wù)開始時(shí)刻一致的算芯,InnoDB默認(rèn)級別柒昏。在SQL標(biāo)準(zhǔn)中,該隔離級別消除了不可重復(fù)讀熙揍,但是還存在幻象讀
  • 串行讀(Serializable):完全串行化的讀职祷,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞

Read Uncommitted這種級別,數(shù)據(jù)庫一般都不會用堪旧,而且任何操作都不會加鎖削葱,這里就不討論了奖亚。

MySQL中鎖的種類

MySQL中鎖的種類很多淳梦,有常見的表鎖和行鎖,也有新加入的Metadata Lock等等,表鎖是對一整張表加鎖昔字,雖然可分為讀鎖和寫鎖爆袍,但畢竟是鎖住整張表,會導(dǎo)致并發(fā)能力下降作郭,一般是做ddl處理時(shí)使用陨囊。

行鎖則是鎖住數(shù)據(jù)行,這種加鎖方法比較復(fù)雜夹攒,但是由于只鎖住有限的數(shù)據(jù)蜘醋,對于其它數(shù)據(jù)不加限制,所以并發(fā)能力強(qiáng)咏尝,MySQL一般都是用行鎖來處理并發(fā)事務(wù)压语。這里主要討論的也就是行鎖。

Read Committed(讀取提交內(nèi)容)

在RC級別中编检,數(shù)據(jù)的讀取都是不加鎖的胎食,但是數(shù)據(jù)的寫入、修改和刪除是需要加鎖的允懂。效果如下

MySQL> select * from class_teacher;
+----+--------------+------------+
| id | class_name   | teacher_id |
+----+--------------+------------+
|  1 | 初三一班     |          1 |
|  3 | 初二一班     |          2 |
|  4 | 初二二班     |          2 |
+----+--------------+------------+

由于MySQL的InnoDB默認(rèn)是使用的RR級別厕怜,所以我們先要將該session開啟成RC級別,并且設(shè)置binlog的模式

SET session transaction isolation level read committed;
SET SESSION binlog_format = 'ROW';(或者是MIXED)
事務(wù)A 事務(wù)B
begin; begin;
update class_teacher set class_name='初三二班' where teacher_id=1; update class_teacher set class_name='初三三班' where teacher_id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
commit;

為了防止并發(fā)過程中的修改沖突蕾总,事務(wù)A中MySQL給teacher_id=1的數(shù)據(jù)行加鎖粥航,并一直不commit(釋放鎖),那么事務(wù)B也就一直拿不到該行鎖生百,wait直到超時(shí)递雀。

這時(shí)我們要注意到,teacher_id是有索引的置侍,如果是沒有索引的class_name呢映之?update class_teacher set teacher_id=3 where class_name = '初三一班';
那么MySQL會給整張表的所有數(shù)據(jù)行的加行鎖。這里聽起來有點(diǎn)不可思議蜡坊,但是當(dāng)sql運(yùn)行的過程中杠输,MySQL并不知道哪些數(shù)據(jù)行是 class_name = '初三一班'的(沒有索引嘛),如果一個(gè)條件無法通過索引快速過濾秕衙,存儲引擎層面就會將所有記錄加鎖后返回蠢甲,再由MySQL Server層進(jìn)行過濾。

但在實(shí)際使用過程當(dāng)中据忘,MySQL做了一些改進(jìn)鹦牛,在MySQL Server過濾條件搞糕,發(fā)現(xiàn)不滿足后,會調(diào)用unlock_row方法曼追,把不滿足條件的記錄釋放鎖 (違背了二段鎖協(xié)議的約束)窍仰。這樣做,保證了最后只會持有滿足條件記錄上的鎖礼殊,但是每條記錄的加鎖操作還是不能省略的驹吮。可見即使是MySQL晶伦,為了效率也是會違反規(guī)范的碟狞。

這種情況同樣適用于MySQL的默認(rèn)隔離級別RR。所以對一個(gè)數(shù)據(jù)量很大的表做批量修改的時(shí)候婚陪,如果無法使用相應(yīng)的索引族沃,MySQL Server過濾數(shù)據(jù)的的時(shí)候特別慢,就會出現(xiàn)雖然沒有修改某些行的數(shù)據(jù)泌参,但是它們還是被鎖住了的現(xiàn)象脆淹。

Repeatable Read(可重讀)

這是MySQL中InnoDB默認(rèn)的隔離級別。我們姑且分“讀”和“寫”兩個(gè)模塊來講解及舍。

讀就是可重讀未辆,可重讀這個(gè)概念是一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí),會看到同樣的數(shù)據(jù)行锯玛,有點(diǎn)抽象咐柜,我們來看一下效果。

RC(不可重讀)模式下的展現(xiàn)

事務(wù)A 事務(wù)B
begin; begin;
select id,class_name,teacher_id from class_teacher where teacher_id=1;idclass_nameteacher_id1初三二班12初三一班1
update class_teacher set class_name='初三三班' where id=1;
commit;
select id,class_name,teacher_id from class_teacher where teacher_id=1;idclass_nameteacher_id1初三三班12初三一班1讀到了事務(wù)B修改的數(shù)據(jù)攘残,和第一次查詢的結(jié)果不一樣拙友,是不可重讀的。
commit;

事務(wù)B修改id=1的數(shù)據(jù)提交之后歼郭,事務(wù)A同樣的查詢遗契,后一次和前一次的結(jié)果不一樣,這就是不可重讀(重新讀取產(chǎn)生的結(jié)果不一樣)病曾。這就很可能帶來一些問題牍蜂,那么我們來看看在RR級別中MySQL的表現(xiàn):

事務(wù)A 事務(wù)B 事務(wù)C
begin; begin; begin;
select id,class_name,teacher_id from class_teacher where teacher_id=1;
idclass_nameteacher_id1初三二班12初三一班1 update class_teacher set class_name='初三三班' where id=1;commit;
insert into class_teacher values (null,'初三三班',1);commit;
select id,class_name,teacher_id from class_teacher where teacher_id=1;idclass_nameteacher_id1初三二班12初三一班1沒有讀到事務(wù)B修改的數(shù)據(jù),和第一次sql讀取的一樣泰涂,是可重復(fù)讀的鲫竞。沒有讀到事務(wù)C新添加的數(shù)據(jù)。
commit;

我們注意到逼蒙,當(dāng)teacher_id=1時(shí)从绘,事務(wù)A先做了一次讀取,事務(wù)B中間修改了id=1的數(shù)據(jù),并commit之后僵井,事務(wù)A第二次讀到的數(shù)據(jù)和第一次完全相同陕截。所以說它是可重讀的。那么MySQL是怎么做到的呢批什?這里姑且賣個(gè)關(guān)子农曲,我們往下看。

不可重復(fù)讀和幻讀的區(qū)別####

不可重復(fù)讀重點(diǎn)在于update和delete渊季,而幻讀的重點(diǎn)在于insert朋蔫。

如果使用鎖機(jī)制來實(shí)現(xiàn)這兩種隔離級別,在可重復(fù)讀中却汉,該sql第一次讀取到數(shù)據(jù)后,就將這些數(shù)據(jù)加鎖荷并,其它事務(wù)無法修改這些數(shù)據(jù)合砂,就可以實(shí)現(xiàn)可重復(fù)讀了。但這種方法卻無法鎖住insert的數(shù)據(jù)源织,所以當(dāng)事務(wù)A先前讀取了數(shù)據(jù)翩伪,或者修改了全部數(shù)據(jù),事務(wù)B還是可以insert數(shù)據(jù)提交谈息,這時(shí)事務(wù)A就會發(fā)現(xiàn)莫名其妙多了一條之前沒有的數(shù)據(jù)缘屹,這就是幻讀,不能通過行鎖來避免侠仇。需要Serializable隔離級別 轻姿,讀用讀鎖,寫用寫鎖逻炊,讀鎖和寫鎖互斥互亮,這么做可以有效的避免幻讀、不可重復(fù)讀余素、臟讀等問題豹休,但會極大的降低數(shù)據(jù)庫的并發(fā)能力。

所以說不可重復(fù)讀和幻讀最大的區(qū)別桨吊,就在于如何通過鎖機(jī)制來解決他們產(chǎn)生的問題威根。

上文說的,是使用悲觀鎖機(jī)制來處理這兩種問題视乐,但是MySQL洛搀、ORACLE、PostgreSQL等成熟的數(shù)據(jù)庫炊林,出于性能考慮姥卢,都是使用了以樂觀鎖為理論基礎(chǔ)的MVCC(多版本并發(fā)控制)來避免這兩種問題。

悲觀鎖和樂觀鎖####

  • 悲觀鎖

它指的是對數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度独榴,因此僧叉,在整個(gè)數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)棺榔。悲觀鎖的實(shí)現(xiàn)瓶堕,往往依靠數(shù)據(jù)庫提供的鎖機(jī)制(也只有數(shù)據(jù)庫層提供的鎖機(jī)制才能真正保證數(shù)據(jù)訪問的排他性,否則症歇,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制郎笆,也無法保證外部系統(tǒng)不會修改數(shù)據(jù))。

在悲觀鎖的情況下忘晤,為了保證事務(wù)的隔離性宛蚓,就需要一致性鎖定讀。讀取數(shù)據(jù)時(shí)給加鎖设塔,其它事務(wù)無法修改這些數(shù)據(jù)凄吏。修改刪除數(shù)據(jù)時(shí)也要加鎖,其它事務(wù)無法讀取這些數(shù)據(jù)闰蛔。

  • 樂觀鎖

相對悲觀鎖而言痕钢,樂觀鎖機(jī)制采取了更加寬松的加鎖機(jī)制。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機(jī)制實(shí)現(xiàn)序六,以保證操作最大程度的獨(dú)占性任连。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷,特別是對長事務(wù)而言例诀,這樣的開銷往往無法承受随抠。

而樂觀鎖機(jī)制在一定程度上解決了這個(gè)問題。樂觀鎖余佃,大多是基于數(shù)據(jù)版本( Version )記錄機(jī)制實(shí)現(xiàn)暮刃。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個(gè)版本標(biāo)識爆土,在基于數(shù)據(jù)庫表的版本解決方案中椭懊,一般是通過為數(shù)據(jù)庫表增加一個(gè) “version” 字段來實(shí)現(xiàn)。讀取出數(shù)據(jù)時(shí)步势,將此版本號一同讀出氧猬,之后更新時(shí),對此版本號加一坏瘩。此時(shí)盅抚,將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息進(jìn)行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當(dāng)前版本號倔矾,則予以更新妄均,否則認(rèn)為是過期數(shù)據(jù)柱锹。

Serializable

這個(gè)級別很簡單,讀加共享鎖丰包,寫加排他鎖禁熏,讀寫互斥。使用的悲觀鎖的理論邑彪,實(shí)現(xiàn)簡單瞧毙,數(shù)據(jù)更加安全,但是并發(fā)能力非常差寄症。如果你的業(yè)務(wù)并發(fā)的特別少或者沒有并發(fā)宙彪,同時(shí)又要求數(shù)據(jù)及時(shí)可靠的話,可以使用這種模式有巧。

這里要吐槽一句释漆,不要看到select就說不會加鎖了,在Serializable這個(gè)級別剪决,還是會加鎖的灵汪!


相信讀到這里的小伙伴,一定有了很大的收獲柑潦。贈人玫瑰,手留余香峻凫。喜歡的話還請點(diǎn)個(gè)贊哈渗鬼。
最后祝大家都能拿到自己滿意的offer!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荧琼,一起剝皮案震驚了整個(gè)濱河市譬胎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌命锄,老刑警劉巖堰乔,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脐恩,居然都是意外死亡镐侯,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門驶冒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苟翻,“玉大人,你說我怎么就攤上這事骗污〕缑ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵需忿,是天一觀的道長诅炉。 經(jīng)常有香客問我蜡歹,道長,這世上最難降的妖魔是什么涕烧? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任月而,我火速辦了婚禮,結(jié)果婚禮上澈魄,老公的妹妹穿的比我還像新娘景鼠。我一直安慰自己,他們只是感情好痹扇,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布铛漓。 她就那樣靜靜地躺著,像睡著了一般鲫构。 火紅的嫁衣襯著肌膚如雪浓恶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天结笨,我揣著相機(jī)與錄音包晰,去河邊找鬼。 笑死炕吸,一個(gè)胖子當(dāng)著我的面吹牛伐憾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赫模,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼树肃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瀑罗?” 一聲冷哼從身側(cè)響起胸嘴,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斩祭,沒想到半個(gè)月后劣像,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摧玫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年耳奕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片席赂。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吮铭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出颅停,到底是詐尸還是另有隱情谓晌,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布癞揉,位于F島的核電站纸肉,受9級特大地震影響溺欧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柏肪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一姐刁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烦味,春花似錦聂使、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至溃论,卻和暖如春屎蜓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钥勋。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工炬转, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人算灸。 一個(gè)月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓扼劈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親菲驴。 傳聞我的和親對象是個(gè)殘疾皇子测僵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容