天天看點

transaction (1)—mysql進階(五十七)

前面說了當設定的buffer_pool_size在1個G内,則不管如何設定,buffer_pool_instances都是一個,當在1個G以上,mysql才支援多個instances設定,每個都有自己獨立的連結清單,多線程的情況下互不幹擾運作。

Show engine innodb status\G

磁盤太慢,記憶體很有必要,buffer_pool在mysql啟動的時候會向系統申請連續的記憶體空間,buffer_pool_instances 和buffer_pool_chunk_size這幾個參數是倍數關系,設定的時候,mysql為了防止浪費記憶體出現碎片,自動會平衡他們的參數。

為了友善管理,裡面有free連結清單,flush連結清單,lru連結清單,

Free連結清單就是申請空閑的緩存頁,flush連結清單就是修改之後的資料,需要更新到磁盤上的,lru連結清單又分為young區域和old區域,這裡面的資料代表最後 使用資料。Select查詢過程是先從磁盤吧資料放入buffer pool緩存頁,有自己的控制塊,吧控制塊放入old區域,如果在buffer_old _block_time,初次和最後一次通路超過這個時間,則會吧資料放入young,這樣可以解決全表查詢資料太大導緻熱資料被記憶體釋放,也可以防止預讀。

連結清單裡面資料那麼多怎麼查詢呢,通過hash表來查詢,key是表空間id+頁号,value就是緩存頁。

多個buffer Pool執行個體 (3)—Buffer Pool(五十六)

為什麼要事務?

我們先建立一個表

mysql> create table account(
    -> id int not null auto_increment comment '自增id',
    -> name varchar(100) comment '客戶名稱',
    -> balance int comment '餘額',
    -> primary key (id
    -> )engine=Innodb charset=utf8;
Query OK, 0 rows affected (0.04 sec)
+----+--------+---------
| id | name   | balance |
+----+--------+---------
|  1 | 狗       |      11
|  2 | 貓       |       2
+----+--------+---------+           

複制

從上我們可以看到狗有11元,貓有2元,現實生活中,如果貓向狗借10元錢,那麼夠會變成1元,貓變成12元。那這兩個操作在代碼裡運作其實執行兩個sql語句。

UPDATE account SET balance = balance - 10 WHERE id = 1;

UPDATE account SET balance = balance + 10 WHERE id = 2;

但如果執行到一半的時候,斷電了或者系統當機,或者各種原因導緻接下來一半不執行,狗的11元減少成功,貓但是還是顯示2元,那麼整個資料就會亂套。怎麼能保證這些和現實中保持一緻呢,于是要把現實中的規則帶入到代碼。

原子性(Atomicity)

現實中,兩個人的轉賬操作是不可分割的,要不壓根沒轉過,要不轉賬成功,不能一個人轉賬成功,另一個人沒有收到錢。Mysql吧這種要麼做就做完整的規則叫做原子性(Atomicity)。但現實中不可分割的操作,在資料庫裡可能要執行多次,比如兩個sql,比如 緩存頁的髒資料還沒有重新整理到磁盤上,最要命的是,任何一個步驟錯了,都會導緻操作執行不下去,就會導緻貓收不到錢。為了保證mysql資料庫的原子性,mysql費盡心機吧已經操作的資料如果異常,就恢複到之前的資料,這是我們後面需要仔細唠嗑的復原。

隔離性(isolation)

現實中兩個人轉賬是互不幹擾的,比如狗向貓轉賬兩次5元,那麼貓肯定會多10元,狗肯定少10元,那麼代碼中的過程是什麼呢?

讀取狗的金額,read(A)

狗的金額-5,A = A-5

吧狗的金額重新整理到磁盤,write(A)

讀取貓的金額,read(B)

貓的金額+5, B =B+5

吧貓的金額重新整理到磁盤,write(B)

現在要操作兩次,如果按順序操作,比如1~6執行完之後,在執行1次1~6的步驟,這樣是沒有問題的,貓會+10,狗會減少10。

但很不幸的是,資料庫真實的操作是這樣的,

事務1:read(A)

事務2:read(A)

事務1:A = A-5

事務1:write(A),這時候A是6

事務1:read(B)

事務1:B=B+5

事務1:write(B),這時候b是7.

事務2:A = A-5,

事務2:write(A),這時候A還是6

事務2:read(B)

事務2:B=B+5

事務2:write(B) 這時候b是12

對于上面那種情況,如果貓加了10元,而狗減了5元,那麼銀行不是虧本了嗎,是以mysql在每個事物之間讓他們隔離開,互不幹擾。

一緻性(Consistency)

我們的生活有形形色色的限制,比如身份證号碼不能重複,聯考分數目前隻能在0~750之間,紅綠燈隻能有三種顔色,買東西時候單價不能為負數等等,隻有符合這些限制才有效,比如有人跟你說今天開車看到個藍色的紅綠燈,你一聽就知道是假的。是以mysql資料庫也是有限制性的。

其實可以從兩方面努力,資料庫本身能給我們保證限制性,比如觸發器檢測金額不能小于0。但這種一般都是不可取的,實際的業務場景裡,我們都是通過程式員,因為更改資料庫的時候檢測是不是金額大于0是非常耗時的,但如果在代碼裡判斷就非常簡單,隻要在編寫業務的時候加個>0的判斷就好。

前面的原子性和隔離性,對一緻性也有很大的影響,如果原子性 和 隔離性不能保證,那麼資料都是錯的,根本就不可能保證一緻性。

但原子性和隔離性一定滿足,就能保證一緻性嗎,這又不一定,因為如果金額成為了負數,這也是不能滿足一緻性限制的。

持久性(Durability)

當我們現實生活中,發生借錢事件後,結果将會永久的儲存下來,是以在mysql中也是如此,比如狗向貓轉賬,成功後,貓的賬單又回到2,恢複到轉賬前的樣子,那樣實不可取。

是以持久性意味着資料必須在磁盤上永久儲存。

事務的概念

綜上所述,Atomicity,Isolution,Consistency,Durability,合在一起就是ACID,mysql為了友善,直接把這四個統一稱為transaction。

事務大緻劃分四個狀态:

活動的(active):事務對應的資料庫操作正在執行中,表示該事務活動的狀态。

部分送出的(partially committed):事務的最後一個操作完成,但因為事務都在記憶體裡進行,還沒有重新整理到磁盤上,這種稱為部分送出。

失敗的(filed):當事務在活動的,部分送出的時候遇到錯誤,如資料庫錯誤,或者斷電等,這時候事務就在失敗狀态。

終止的(aborted):當在活動和部分送出之後,出錯怎麼辦呢,失敗之後就終止,并且mysql會吧目前的資料恢複到操作前的狀态,我們叫這個為復原。

送出的(commited):如果成功呢,則就持久化到磁盤上。