mysql第二天 鎖,mysql第二天
 
如果沒有鎖,那麼並發性會更強,但是資料安全性會有問題。因此資料庫會給資料加鎖。
共用鎖定與獨佔鎖定
也就是讀寫鎖,共用鎖定可以疊加共用鎖定但是不能加獨佔鎖定, 獨佔鎖定則不能疊加。根據隔離等級等等,mysql會隱式的給資料自動加鎖此外還可以使用share in model, for update 等語句顯示的加鎖
粒度鎖
粒度越細,維護鎖的開銷越大,並發性越高,資料越不安全。 通常有如下兩種 
 - 行鎖 
 只給一行資料加鎖 
 - 表鎖 
 給整張表加鎖, 一般Alter table會使用表鎖
意圖鎖定
mysql為了提高衝突監測效能而存在的一種鎖。是給其上一級所加的鎖,所以在mysql中通常為表鎖。 
 比如一個事務,給兩行加了獨佔鎖定,又有一個事務想要給整個表加共用鎖定,這個時候就要去查看所有的表的行是否有鎖策略不能加共用鎖定。 如果有了意圖鎖定,那麼事務1就能再給兩行加獨佔鎖定的同時,給整個表加IX, 這樣事務2不用遍曆就能知道不可以加S鎖了。
悲觀鎖與樂觀鎖
A,B兩個人同時在系統上進行操作,比如要修改一份訂單。 當A正在修改準備提交前向上廁所,這兒時候B修改完訂單並且提交了。 這個時候A回來了再提交就會出現問題,B的修改被覆蓋了。 
 - 悲觀鎖 
 for update, share in model語句 
 使用悲觀鎖,則會在操作期間全程對資料進行加鎖,其他人不能再次修改。這樣會造成比較長時間的阻塞。 
 適用於短事務,寫量比較大的情況。 
 - 樂觀鎖 
 樂觀鎖通過在資料庫中新增一個version欄位,操作後給version + 1. 提交時比較,如果比資料庫中的大,則提交。大概的代碼是:
    if(connection.update("update set name='123' where id=1 and version < #current_version#") > 0){        // 表示更新成功了    }
這種適用於讀多,寫少,並且寫有可能會用很長時間的情況。
死結
比如有兩個事物: 
事物1
update table1 set name='1' where id=1;// sleep 1update table1 set name='2' where id=2;commit;
事物2
update table1 set name='2' where id=2;// sleep 2update table1 set name='1' where id=1;commit;
上面的語句如果恰巧一起執行到sleep1 和sleep2,那麼就會造成死結。 一般有三種做法解決:
 - 一次鎖所有資料
 
 - 保持鎖的順序
 
 - 允許死結,然後kill掉代價最小的事務。復原之
 
間隙鎖
執行select .. from where id between這樣的語句的時候鎖定這一區間,不能插入或者刪除資料,以防止幻讀。
MVCC 多版本並發控制
mysql維護一個系統版本號碼,每次有新的事物開始的時候遞增。 
每行後面儲存兩個隱藏列。 一個建立時版本號碼C,一個刪除時版本號碼D
 - INSERT 新增的行往C裡寫入當前系統版本號碼。 這樣新事物可以通過這個版本號碼保證不查到他
 
 - DELETE 為刪除的行寫D欄位為當前系統版本號碼。 
 
 - UPDATE 插入一行新資料寫C為當前系統版本號碼,老資料寫D為當前系統版本號碼。
 
 - SELECT 的時候只查 C<=目前的版本 && (D > 目前的版本 || D is not defined) 這樣主要是為了在不加鎖的情況下,一個事務能夠讀取到事務開始前已經存在且未被刪除,且沒有經過修改的資料。 也就是解決髒讀的問題。即該事物開始之後的其他事務的各種修改事務提交都不會對當前事務的讀取產生影響。同時也解決了幻讀的問題
 
語句與鎖
 - InnoDB 的行鎖是基於索引的,如果沒有索引,或者不能使用索引則是表鎖
 
 - select … from 一致性非阻塞讀,不上鎖。
 
 - select … from where lock in share mode 共用鎖定
 
 - select … from where … for update 獨佔鎖定
 
 - update .. where 獨佔鎖定
 
 - delete … from 獨佔鎖定 
下面的例子來看鎖的排他性 
事務1 
 set autocommit=0; begin; SELECT * FROM biz_pay_task where id = 1 FOR UPDATE; // wait commit;
事務2
 set autocommit=0; begin; SELECT * FROM biz_pay_task where id = 1 LOCK IN SHARE MODE; commit;
事務2在執行SELECT LOCK IN SHARE MODE的時候會阻塞,知道事務1commit之後才會完成。
 
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。