數(shù)據(jù)(data)
? ? 數(shù)據(jù)是人類世界非常重要的存在。世界上的一切事物是一部分數(shù)據(jù)的集合,那么理論上我們就可以創(chuàng)造出一切事物城瞎,前提是獲得相應(yīng)的數(shù)據(jù)并建立起一個模型(對事物的描述)。以印刷術(shù)為例,每一個字的形狀都是一個數(shù)據(jù)狡刘,人們以對這些數(shù)據(jù)的認知對每一個字都建立了一個模型,然后可以通過這些模型就可以印出相應(yīng)的字符困鸥。進入電子信息時代嗅蔬,數(shù)據(jù)得到了更廣泛,更深度的使用疾就。例如在醫(yī)學(xué)澜术,航天,機器人(人工智能)猬腰。
? ? 越復(fù)雜的事物我們越難描述(建立模型)瘪板,因為越復(fù)雜的事物包含的數(shù)據(jù)元素就越龐大,此時我們需要將收集到的數(shù)據(jù)存儲起來進行分類管理漆诽,需要時讀取侮攀,這時就引入了數(shù)據(jù)庫。
數(shù)據(jù)庫DB(database)
? ? 數(shù)據(jù)庫從很早就開始存在厢拭,例如古時候用于記賬的賬簿兰英,記錄個人信息的檔案庫,藏在某處的武林秘籍等等供鸠。到了電子信息時代畦贸,已經(jīng)可以實現(xiàn)將數(shù)據(jù)存儲在計算機的磁盤上了。這里定義計算機磁盤空間中的長久存儲的大量數(shù)據(jù)的集合就是一個數(shù)據(jù)庫(database),使用磁盤作為數(shù)據(jù)庫有數(shù)據(jù)永久性保存薄坏,查詢管理方便等優(yōu)點趋厉。
數(shù)據(jù)庫系統(tǒng)DBS(database system)
? ? 數(shù)據(jù)庫系統(tǒng)一般由數(shù)據(jù)庫、數(shù)據(jù)庫管理系統(tǒng)(及其開發(fā)工具)胶坠、應(yīng)用系統(tǒng)君账、數(shù)據(jù)庫管理員構(gòu)成。該系統(tǒng)維護數(shù)據(jù)庫的正常生命周期沈善。
數(shù)據(jù)庫管理系統(tǒng)DBMS(database manager system)
? ? 數(shù)據(jù)庫管理系統(tǒng)是位于用戶與操作系統(tǒng)之間的一層數(shù)據(jù)管理軟件乡数。這個系統(tǒng)方便用戶操作,維護數(shù)據(jù)庫闻牡。常用的DBMS有:MySQL净赴、Oracle、DB2罩润、SQLServer等玖翅。本文要討論的是MySQL。
? ?
? ? 當我們使用計算機磁盤作為數(shù)據(jù)庫存儲數(shù)據(jù)割以,使用相應(yīng)的DBMS進行訪問操作數(shù)據(jù)之后烧栋,單用戶訪問操作數(shù)據(jù)庫是沒有問題的,但是單用戶訪問的效率實在太低拳球,此時我們想實現(xiàn)多用戶并發(fā)訪問审姓。但是此時就會出現(xiàn)問題:
? ? 1.用戶1讀取了某數(shù)據(jù),準備使用祝峻。
? ? 2.用戶2在之后修改了該數(shù)據(jù)魔吐。
? ? 3.用戶1在使用之前忘記了自己讀的數(shù)據(jù),再次讀取莱找。
那么我們希望能夠解決這些問題來實現(xiàn)多用戶并發(fā)訪問數(shù)據(jù)庫酬姆。此時我們對DBMS的設(shè)計引入以下規(guī)則:
? ?
? ? 事務(wù)(Transaction):完成某個需求需要做的一連串的操作稱為一個事務(wù),事務(wù)是DBMS的執(zhí)行單元奥溺。
? ? 事務(wù)具有以下特性:
? ? ? ? 原子性:事務(wù)是不可分割的辞色,完成事務(wù)的步驟要么全部不做,要么全部做完浮定。(rollback&commit)
? ? ? ? 一致性:事務(wù)執(zhí)行過程中操作的數(shù)據(jù)必須是一致的相满。(不同需求下對于一致性的要求不同)
? ? ? ? 隔離性:多個事務(wù)并發(fā)執(zhí)行的時候,多個事務(wù)之間操作的數(shù)據(jù)互不影響桦卒。(隔離性實現(xiàn)一致性)
? ? ? ? 持久性:事務(wù)一旦提交立美,數(shù)據(jù)就永久存儲在數(shù)據(jù)庫中,即使是產(chǎn)生故障也不能影響方灾。(recovery)
? ?
? ? 由于不同需求下對于并發(fā)訪問的產(chǎn)生的結(jié)果要求不同建蹄,提出了以下四大隔離級別:
? ? ? ? read uncommitted:讀未提交
? ? ? ? ? ? 此隔離級別下碌更,事務(wù)會讀到未提交事務(wù)的數(shù)據(jù)。
? ? ? ? read committed:讀已提交
? ? ? ? ? ? 此隔離級別下洞慎,事務(wù)會讀到已經(jīng)提交事務(wù)的數(shù)據(jù)痛单。
? ? ? ? repeatable read:可重復(fù)讀
? ? ? ? ? ? 此隔離級別下,其他事務(wù)對于數(shù)據(jù)的修改不會影響到本事務(wù)讀數(shù)據(jù)劲腿。
? ? ? ? serializable:可串行化
? ? ? ? ? ? 此隔離級別下旭绒,所有事務(wù)串行化(排隊)執(zhí)行。
? ? ? ?
? 并發(fā)訪問問題匯總:
? ? 1.修改丟失:
? ? ? ? 1)事務(wù)1讀取了數(shù)據(jù)對象A=3谆棱,保存下來賦值為B1。
? ? ? ? 2)事務(wù)2讀取了數(shù)據(jù)對象A=3圆仔,保存下來賦值為B2垃瞧。
? ? ? ? 3)事務(wù)1修改了數(shù)據(jù)對象A=B1+1=4。
? ? ? ? 4)事務(wù)2修改了數(shù)據(jù)對象A=B2+1=4坪郭。
? ? ? ? 場景:多窗口賣票个从。
? ? ? ? 窗口1,2同時知道已經(jīng)賣了3張票歪沃,然后在同一時間窗口1賣出了一張票嗦锐,窗口2也賣出了一張票,本應(yīng)該賣出了5張沪曙,結(jié)果只賣了4張奕污。
? ? 2.臟讀:事務(wù)2修改數(shù)據(jù)未提交,事務(wù)1讀取了數(shù)據(jù)液走。
? ? ? ? 1)事務(wù)2修改了數(shù)據(jù)A=3碳默,操作未完成...
? ? ? ? 2)事務(wù)1讀取到了數(shù)據(jù)對象A=3。
? ? ? ? 3)事務(wù)2修改了數(shù)據(jù)A=2缘眶,操作完成嘱根。
? ? ? ? 場景:銀行轉(zhuǎn)賬
? ? ? ? X向Y轉(zhuǎn)賬,銀行中X賬戶減錢巷懈,Y還沒加錢该抒,X此時查看了兩個賬戶。
? ? 3.不可重復(fù)讀:事務(wù)兩次讀取的數(shù)據(jù)不同顶燕。
? ? ? ? ①事務(wù)1讀取數(shù)據(jù)A之后凑保,事務(wù)2修改了A并提交,事務(wù)1再讀涌攻。
? ? ? ? ? ? 1)事務(wù)1讀取數(shù)據(jù)A愉适。
? ? ? ? ? ? 2)事務(wù)2修改A并提交。
? ? ? ? ? ? 3)事務(wù)1讀A癣漆。
? ? ? ? ? ? 場景:查看銀行余額维咸,查詢完成之前,之后再有人轉(zhuǎn)賬余額都不應(yīng)該變化。
? ? ? ? ②幻讀:事務(wù)1讀取了數(shù)據(jù)之后癌蓖,事務(wù)2插入或者刪除了某些數(shù)據(jù)并提交瞬哼,事務(wù)1再讀。
? ? ? ? ? ? 1)事務(wù)1讀取了一個范圍內(nèi)的數(shù)據(jù){A租副,B坐慰,C......}。
? ? ? ? ? ? 2)事務(wù)2插入了數(shù)據(jù)D到此范圍并提交用僧。
? ? ? ? ? ? 3)事務(wù)1讀此范圍發(fā)現(xiàn)新增了D结胀,不一致。
? ? ? ? ? ? 場景:網(wǎng)站實時統(tǒng)計某一時間在線用戶人數(shù)责循,在統(tǒng)計完成之前后面再有新增的用戶記錄都不應(yīng)該沒查詢到糟港。
? ? ? ? ? ?
? ? 不同的隔離級別與并發(fā)問題對應(yīng)關(guān)系:
? ? ? ? 1.修改丟失:
? ? ? ? ? ? 這種問題屬于邏輯上的問題,數(shù)據(jù)庫是處理不了的院仿。以賣票為例秸抚,當有窗口在售票的時候,其他窗口就應(yīng)該等該窗口售完票之后修改了售票數(shù)額再進行讀取余額進行修改歹垫。所以應(yīng)該由程序進行控制剥汤。
? ? ? ? 2.臟讀:read uncommitted隔離下會產(chǎn)生臟讀,read committed以上的級別都處理了臟讀排惨。
? ? ? ? 3.不可重復(fù)讀:read committed以下隔離級別有不可重復(fù)讀吭敢,repeatable以上級別處理了該問題(有一些DBMS沒有處理幻讀的問題)。
下面介紹MySQL處理這些問題并實現(xiàn)事務(wù)四大特性的原理:
首先我們先引進鎖的概念:
? ? ? ? 目前在計算機中對于共享數(shù)據(jù)的并發(fā)訪問大多只能通過“鎖”來進行處理暮芭。在數(shù)據(jù)庫中也引進了兩種鎖的概念:悲觀鎖與樂觀鎖省有。
? ?
?
悲觀鎖:
? ? ? ? 顧名思義:悲觀鎖及在事務(wù)對數(shù)據(jù)進行訪問的時候,悲觀地認為之后會有其他事務(wù)會訪問該數(shù)據(jù)并進行修改而在數(shù)據(jù)上加上一把鎖谴麦,而阻塞其他事務(wù)蠢沿。其中悲觀鎖分為共享鎖和排他鎖。
? ? ? ? ? ? 共享鎖(Share Lock):簡稱S鎖
? ? ? ? ? ? 共享鎖又稱為讀鎖匾效。若事務(wù)T對數(shù)據(jù)對象A加上S鎖舷蟀,則只事務(wù)T可以讀A但是不能修改A,其他任何事務(wù)只能再對A加S鎖面哼,而不能加X鎖 野宜,直到T釋放A上的鎖。? ? ? ? ? ?
? ? ? ? ? ? 排他鎖(eXclusive Lock):簡稱X鎖
? ? ? ? ? ? 排他鎖又稱為寫鎖魔策。若事務(wù)T對數(shù)據(jù)對象A加上X鎖匈子,則只允許T讀取和修改A,其他任何事務(wù)都不能對A加任何類型的鎖 闯袒,直到T釋放A上的鎖虎敦。
注意這里的兩個命題:
1.事務(wù)對A加上了X鎖(條件)能讀寫A(結(jié)果)
2.事務(wù)對A加上了S鎖(條件)能讀A(結(jié)果)
是充分條件游岳,不是必要條件。
即:
1.事務(wù)對A能讀寫A(條件)就加上了X鎖(結(jié)果)
2.事務(wù)對A能讀A(條件)就加上了S鎖(結(jié)果)
這是不成立的其徙。
上述粗體字段就是對前半命題的補充胚迫,拿其他任何事務(wù)都不能對A加任何類型的鎖舉例:
這里是定義了,加了X鎖之后唾那,不能加其他的鎖访锻,而不是不允許其他事務(wù)讀取A了。這里只是定義了加鎖操作之間的互斥關(guān)系闹获。
樂觀鎖:
? ? ? ? 顧名思義:這是一個樂觀的“鎖”期犬,其實稱其為樂觀控制(驗證)法更為準確。即事務(wù)在訪問數(shù)據(jù)的時候避诽,樂觀地認為不會有其他事務(wù)對數(shù)據(jù)進行修改龟虎,不阻塞任何事務(wù),在之后再對該數(shù)據(jù)進行訪問的時候會驗證其是否和之前訪問的數(shù)據(jù)是一致的茎用。
下面討論使用這兩種鎖如何實現(xiàn)事務(wù)四大特性?
? ? 1.理論上遣总,只使用悲觀鎖是可以實現(xiàn)的:
? ? ? ? 1)在讀之前要加共享鎖睬罗。
? ? ? ? 2)在寫之前要加排他鎖轨功。
? ? 在這種情況下,確實實現(xiàn)了事務(wù)的四大特性容达,但是因為鎖的特性會導(dǎo)致古涧,寫操作會阻塞大量的讀操作(讀操作占了數(shù)據(jù)庫訪問中很大的比重),嚴重影響了并發(fā)訪問程度花盐,而且會很容易導(dǎo)致死鎖的發(fā)生(事務(wù)之間互相等待釋放鎖羡滑,解決死鎖有多種方式,這里不具體討論)算芯。
? ? 2.排他鎖加樂觀鎖柒昏,即多版本并發(fā)控制。
? ? ? ? 1)讀不加鎖熙揍。
? ? ? ? 2)寫之前加排他鎖职祷。
? ? ? ? 3)維護多個版本的數(shù)據(jù)供不同的事務(wù)讀取。(不同隔離級別情況不同届囚,下面有介紹)有梆。? ? ? ?
? ? 多版本并發(fā)控制(MutiVersion Concurrency Control),簡稱MVCC意系。它使得大部分支持行鎖的事務(wù)引擎泥耀,不再單純的使用行鎖來進行數(shù)據(jù)庫的并發(fā)控制,取而代之的是把數(shù)據(jù)庫的行鎖與行的多個版本結(jié)合起來蛔添,只需要很小的開銷,就可以實現(xiàn)非鎖定讀痰催,從而大大提高數(shù)據(jù)庫系統(tǒng)的并發(fā)性能兜辞。
? ? 這里引入新概念:行鎖。行鎖指悲觀鎖的粒度(即加鎖的對象單位)陨囊,其中有行鎖弦疮,表鎖,頁鎖蜘醋,數(shù)據(jù)庫鎖等等胁塞。
MySQL(InnoDB)實現(xiàn)事務(wù)四大特性的原理:? ?
概念簡述:
1.undo log(撤銷)
? ? undo log記錄數(shù)據(jù)的多版本快照,事務(wù)在修改數(shù)據(jù)之前會將舊版本的數(shù)據(jù)復(fù)制到undo log压语,讀操作不寫undo log啸罢。
? ? 存在形式:會分配到一定的內(nèi)存(cache),也會寫入磁盤(ibdata1文件)胎食。
? ? 寫入方式:按修改操作順序?qū)懭肴挪牛环质聞?wù)。
? ? ? ? 1)用于事務(wù)的回滾而實現(xiàn)原子性厕怜。
? ? ? ? 2)用于事務(wù)讀操作匹配版本實現(xiàn)一致性衩匣,隔離性。
? ? ? ?
2.redo log (重做)
? ? 事務(wù)在不會直接覆蓋修改數(shù)據(jù)庫磁盤中的數(shù)據(jù)(以下稱為data file)粥航,會先復(fù)制一份數(shù)據(jù)到redo cache中進行修改琅捏,然后寫到redo file之后,再修改data file递雀。
? ? 存在形式:會分配到一定的內(nèi)存(cache)柄延,也會寫入磁盤(ib_logfile0、ib_logfile1文件)缀程。
? ? 寫入方式:按修改操作順序?qū)懭胨寻桑环质聞?wù)。
? ? redo log主要用于維護數(shù)據(jù)的持久性杨凑。
3.DATA_TRX_ID滤奈、DATA_ROLL_PTR、DELETE BIT
? ? 在MySQL表中有三個隱藏字段:
? ? DATA_TRX_ID:事務(wù)修改當前行數(shù)據(jù)的時候會將這個字段記錄為自己的事務(wù)ID
? ? DATA_ROLL_PTR:回滾指針撩满,事務(wù)修改當前行數(shù)據(jù)的時候?qū)⑦@個字段記錄指向undolog中上一次修改該行的記錄蜒程。
? ? DELETE BIT:事務(wù)修改當前行數(shù)據(jù)的時候記錄標記為“被刪除”。
? ?
? ? 事務(wù)修改數(shù)據(jù)的流程分析:
? ? 事務(wù)將數(shù)據(jù)對象A從數(shù)據(jù)庫(磁盤)中復(fù)制到redo cache buffer中進行修改鹦牛,在修改之前再復(fù)制一份填寫刪除標識字段搞糕,將其回滾指針指向undo中上一條記錄,放到undo cache buffer中曼追,然后將redo cache中的數(shù)據(jù)副本中的trxid設(shè)為自己的事務(wù)id窍仰,undo&redo cache每隔一段時間(1秒)刷到undo&redo file,redo file寫入之后將寫入redo file的數(shù)據(jù)覆蓋寫入data file數(shù)據(jù)礼殊。
? ? 事務(wù)修改數(shù)據(jù)的流程圖解:
?
? ?
? ?
? ? ①原子性:事務(wù)沒完成驹吮,可以通過回滾指針一條一條記錄往前反向復(fù)原针史,直到事務(wù)修改之前的記錄版本。
? ?
? ? ②一致性&隔離性(因為一致性依賴于隔離性碟狞,這里一起討論):
? ? ? ? read uncommitted:
? ? ? ? 讀不加鎖啄枕,寫加X鎖。
? ?
? ? ? ? read committed&repeatable read:
? ? ? ? 事務(wù)讀操作每次都是結(jié)合read view在data+undo file中匹配適合的數(shù)據(jù)族沃。(MVCC)
? ? ? ?
? ? ? ? 新概念:
? ? ? ? read view:
? ? ? ? 每個事務(wù)在創(chuàng)建的時候InnoDB(MySQL數(shù)據(jù)庫引擎)都會記錄當前系統(tǒng)中的活動事務(wù)id(不包含committed以及本事務(wù)的id)到一個副本-->read view频祝。這個副本的功能是記錄了對與本事務(wù)來說應(yīng)該隔離的事務(wù)(不可見)。
? ? ? ? 注:事務(wù)id是按照創(chuàng)建順序遞增分配的脆淹。? ? ? ? ? ? .
? ? ? ?
? ? ? ? 1.將data+undo file中的符合條件的數(shù)據(jù)全部找出(多版本)常空。將排在第一的數(shù)據(jù)的transaction_id賦值給trx_id,read view中的最小值id為trx_min盖溺,最大值為trx_max漓糙。
? ? ? ? 2.如果trx_id<trx_min,說明創(chuàng)建該版本數(shù)據(jù)的事務(wù)是在read view創(chuàng)建之前(也就是在當前事務(wù)創(chuàng)建之前)就已經(jīng)committed了烘嘱。跳到步驟6昆禽。
? ? ? ? 3.如果trx_id>trx_max,說明創(chuàng)建該版本數(shù)據(jù)的事務(wù)是在read view創(chuàng)建之后(也就是當前事務(wù)創(chuàng)建之后)創(chuàng)建的蝇庭,此版本數(shù)據(jù)不可見醉鳖。跳到步驟5
? ? ? ? 4.如果trx_min <= trx_id<= trx_max,說明創(chuàng)建該版本數(shù)據(jù)的事務(wù)在當前事務(wù)創(chuàng)建之前創(chuàng)建的遗契,(但是不確定是否是在當前事務(wù)創(chuàng)建之前提交的)辐棒。拿trx_id遍歷匹配read view:
? ? ? ? ? ? 1)如果有相等的事務(wù)id病曾,說明創(chuàng)建該版本的事務(wù)在當前事務(wù)創(chuàng)建的時候還是活躍的牍蜂。此版本數(shù)據(jù)也不可見,跳到步驟5泰涂;
? ? ? ? ? ? 2)如果沒有匹配到相等的事務(wù)id鲫竞,說明創(chuàng)建該版本的事務(wù)在當前事務(wù)創(chuàng)建的之前就提交了,只不過它比一些在它之前創(chuàng)建的事務(wù)提交得早逼蒙。調(diào)到步驟6从绘。
? ? ? ? 5.用回滾指針找到上一版本數(shù)據(jù),將其trasaction_id賦值給trx_id是牢,跳到步驟2僵井。
? ? ? ? 6.該版本數(shù)據(jù)是可見的,返回該數(shù)據(jù)到讀取操作驳棱。
? ? ? ? 在rc隔離級別下:在事務(wù)創(chuàng)建之初以及每次read的時候都會創(chuàng)建一份read view批什。
? ? ? ? 在rr隔離級別下:只在事務(wù)創(chuàng)建的時候創(chuàng)建一份相對與該事務(wù)全局的read view。
? ? ? ? serializable:
? ? ? ? 讀加S鎖社搅,寫加X鎖驻债。
? ? ? ?
? ? ③持久性:因為所有數(shù)據(jù)修改都是在提交完成之前已經(jīng)通過redo log寫到了服務(wù)器數(shù)據(jù)庫磁盤中去了乳规。即使之后數(shù)據(jù)庫故障都可以通過redo中的記錄進行恢復(fù)。(根據(jù)undo進行的rollback操作也會被寫入redo合呐,也就是說恢復(fù)數(shù)據(jù)庫的時候暮的,rollback操作也會重新執(zhí)行)。
? ? ? ?
? ? ? ?
? ?
?