這段時間接觸了許多資料庫,比如mysql,redis,mongo等。因此生了總結一些筆記的念頭,故而打算複習以前學過的一些知識,所以會將以往做的一些筆記記錄下來。如果在寫部落格的時候能夠引發相關思考,那便再好不過了。
本篇部落格的主人公則是mysql,主要說一說資料庫事務和它的隔離級別。
1.事務
什麼是事務呢?官方一些來說,事務就是恢復和併發控制的基本單位。
為什麼說是基本單位呢?我們在做乙個需求的時候,往往不是乙個sql語句就可以完成所有的更改,通常都需要一系列的操作才可以達到預期的目的。而這一系列的操作呢,就可以看作乙個事務。或者說,我們可以人為地將它看作乙個「原子操作」。類似於+1和-1操作。當乙個事務執行之後,就相當於+1,那麼我如果後悔了呢?我不想加一了,怎麼辦呢?那就執行回滾,也就是-1操作。
那麼事務有什麼用處呢?上面說了,事務是恢復和併發控制的基本單位,那麼主要作用自然就是恢復和進行併發控制咯。
舉個例子,拿網上購物來說,當我們進行交易的時候,通常需要經過以下幾個步驟:
①更改商品庫存資訊;
②儲存客戶付款資訊,生成訂單並將其儲存到資料庫中;
③更改使用者的相關資訊,比如購物車資訊,下單資訊等。
如果事情順利,那麼這一系列操作自然可以順利執行,也就是說交易成功。但是萬一在交易的時候,突然有內鬼怎麼辦?
哈哈,開玩笑啦。但是你想啊,這一系列的操作,難免會出現一些極端情況,比如突然沒有訊號,或者手機關機了,又或者庫存資訊異常了,這都會導致整個交易過程失敗。那既然失敗了,一些操作結果自然就要不得。比如我這一系列操作有a、b、c,我在c卡殼了,那a、b的執行結果肯定就要不得了。那怎麼辦,把這一系列操作弄成乙個事務唄,要是中間出錯了,那就乖乖回滾,撤銷之前的操作。要是成功了,那自然就皆大歡喜。
2.事務的屬性
在第一點裡,我們有說到,我們可以人為地將事務看作乙個「原子操作」,這其實是事務的屬性之一:原子性。
事務必須滿足四個屬性,也就是原子性,一致性,隔離性,永續性。也就是我們一直念叨的acid。
①原子性
什麼是原子性呢?很顯然,我們一般認為原子是不可再分割的,所以乙個事務是乙個不可分割的整體。這樣的話呢,當執行事務的時候,就避免了只有部分事務完成,也避免了只執行了部分操作而帶來的錯誤。咱要麼全部執行,要麼全都不執行。
要不然,在上面的網購的例子裡,倘若我在第三步的時候嗝屁了,要是不對①②的操作進行撤回,那麼資料庫裡存的資料就是錯誤的,因為我根本就沒有交易成功呀,但資料庫裡卻有我的訂單資訊,豈不怪哉。
②一致性
一致性,其實不太好理解。我最初接觸它的時候,我就在想,到底是什麼玩意一致?
後來才發現,一致性指的是,乙個事務在執行之前和執行之後,資料庫裡面的資料,必須保持一致。
什麼意思呢,拿銀行轉賬來說,轉賬前後,這兩個賬戶的金額之和是不變的。這個就是一致性。
③隔離性
隔離,和誰隔離?作為乙個風度翩翩的事務,那自然要和其他事務保持一定的距離。因此,隔離性所針對的物件,便是其他的事務,這一般說的是在併發情況下。
也就是說,由併發事務所做出的修改,需要與任何其他併發事務所做出的修改隔離。怎麼理解呢?
舉個例子,對於一對事物a1和a2,對於a1來說,a2要麼在a1開始之前就已經結束了,要麼就在a1結束之後才開始執行。
因此,總的來說,當事務檢視資料庫的時候,資料所處的狀態,要麼是另乙個事務修改它之前的狀態,要麼就是另乙個事務修改它之後的模樣。作為乙個有素養的事務,才不會去檢視中間狀態的資料呢。
為啥要這樣?當然是為了保證資料的安全性咯。要是出現幻讀,那可就不好玩了。
④永續性
永續性,也叫永久性。世事無絕對,既然敢叫持久,那肯定有一些東西。什麼叫永續性呢?
對於記憶體資料庫來說,一旦斷電或者出現其他故障而關閉,那麼這些資料可就沒咯。咻~的一下就沒了。如果事前沒有整個快照或者寫入磁碟,而裡面又恰好有一些重要資料,那麼您就可以準備給自己做人工呼吸了,因為這些資料已成 過往雲煙,再也無法回到當初的模樣。
而對於mysql來說,事務的永久性,自然也體現在將資料寫入磁碟。記憶體中的資料都是鏡花水月,轉瞬即逝,只有寫入磁碟的資料,才可算得上持久。對於事務來說,寫入磁碟的並不是相關資料,而是對應的操作,update,insert 或者delete。事務完成之後呢,這些操作就會被寫入磁碟。倘若你需要恢復操作,那麼就可以根據對應的命令,進行手動回滾,這樣就可以回到事務執行以前的狀態。這裡可以了解一下commit和rollback。
在這裡,不得不稱讚一下資料庫日誌,前些天我做一些需求, 對一批資料進行一系列規則的操作,大概有六百萬資料。由於心大,因此沒有做備份。誰知道新來的實習生錯誤操作,把對應的表刪除了,他一臉懵逼的問我怎麼辦........我??? 好在日誌記錄了相關命令,發現是刪除命令只是簡單的delete,所以恢復了過來。否則,產品會發狂,我也會發狂......
3.併發操作所帶來的資料不一致性
上面我們說到,事務是併發控制的基本單位,保證事務的acid自然是義不容辭。但是資料庫基本上都是多使用者共享資料庫資源,也就是說多個使用者可以同時操作相同的資料。
如果是序列操作,即事務順序執行,那自然沒啥大問題。但是倘若是並行控制,資料庫同時接受多個事務,併發操作有可能會破壞事務的acid屬性。
當多個使用者同時訪問乙個資料庫,倘若他們的事務同時操作相同的資料,而又不曾加鎖,那麼就很有可能會導致資料不一致性。
具體包括:更新丟失,髒讀,不可重複讀。
①更新丟失
在無鎖的併發操作下,如果兩個事務同時更新一行資料,乙個事務對資料的更新將很大可能把另乙個事務的更新覆蓋。比如多執行緒計算的時候,更新丟失很大機率會導致計算結果出錯。
②髒讀髒讀,很明顯,就是說讀到了髒資料。什麼叫髒資料呢,就是未提交的資料。乙個事務讀取了另乙個事務的未提交的資料,這是很不安全的。萬一該事務回滾了呢?這樣的話,這個資料就被撤銷了。這樣的話,髒讀之後,該事務的執行結果也不見得正確。
③不可重複讀
不可重複讀,是針對於讀取結果來的。當乙個事務對同一行資料讀取兩次,但卻得到不同的結果,這便是不可重複讀。
若是細分,則有以下兩種情況:
4.事務的隔離級別
第三點說的這幾種情況,乍一看,似乎覺得資料庫用起來很不安全。不過,作為乙個風度翩翩的資料庫,自然會有相應的對策去避免以上的幾種情況咯。
在標準的sql規範中,定義了四個事務隔離級別,來避免上面的幾種情況。而不同的隔離級別,對事物的處理也是不同的。下面就來認識一下:
事務的隔離級別越高,就越能夠保證事務的完整性和統一性。當然,沒有完美的盛宴,級別越高,對併發效能的影響也就越大。對於mysql來說,預設的隔離級別是可重複讀,正好可以避免更新丟失、髒讀、不可重複讀。對於其他的一些資料庫,比如oracle,一般將隔離級別設定為讀已提交,它可以避免髒讀,而且擁有較好的併發效能。而對於不可重複讀、髒讀、第二類丟失更新等這些併發問題,則可以適當地用悲觀鎖或者樂觀鎖來進行控制。
資料庫事務隔離級別
資料庫事務的隔離級別有4個,由低到高依次為read uncommitted read committed repeatable read serializable,這四個級別可以逐個解決髒讀 不可重複讀 幻讀這幾類問題。可能出現 不會出現 髒讀不可重複讀 幻讀read uncommitted rea...
資料庫事務隔離級別
資料庫事務的隔離級別有4個,由低到高依次為read uncommitted read committed repeatable read serializable,這四個級別可以逐個解決髒讀 不可重複讀 幻讀這幾類問題。可能出現 不會出現 髒讀不可重複讀 幻讀read uncommitted rea...
資料庫事務隔離級別
資料庫事務的隔離級別有4個,由低到高依次為read uncommitted read committed repeatable read serializable 這四個級別可以逐個解決髒讀 不可重複讀 幻讀 這幾類問題。可能出現 不會出現 髒讀不可重複讀 幻讀read uncommitted re...