• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            兔子的技術(shù)博客

            兔子

               :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

            留言簿(10)

            最新評論

            閱讀排行榜

            評論排行榜

            摘自 

            《深入淺出MySQL——數(shù)據(jù)庫開發(fā)、優(yōu)化與管理維護》

            20.3.3 InnoDB的行鎖模式及加鎖方法

            InnoDB實現(xiàn)了以下兩種類型的行鎖。 

            ? 共享鎖(S):允許一個事務(wù)去讀一行,阻止其他事務(wù)獲得相同數(shù)據(jù)集的排他鎖。

            ? 排他鎖(X):允許獲得排他鎖的事務(wù)更新數(shù)據(jù),阻止其他事務(wù)取得相同數(shù)據(jù)集的共享讀鎖和排他寫鎖。

            另外,為了允許行鎖和表鎖共存,實現(xiàn)多粒度鎖機制,InnoDB還有兩種內(nèi)部使用的意向鎖(Intention Locks),這兩種意向鎖都是表鎖。

            ? 意向共享鎖(IS):事務(wù)打算給數(shù)據(jù)行加行共享鎖,事務(wù)在給一個數(shù)據(jù)行加共享鎖前必須先取得該表的IS鎖。

            ? 意向排他鎖(IX):事務(wù)打算給數(shù)據(jù)行加行排他鎖,事務(wù)在給一個數(shù)據(jù)行加排他鎖前必須先取得該表的IX鎖。

            上述鎖模式的兼容情況具體如表20-6所示。

            表20-6     InnoDB行鎖模式兼容性列表

            請求鎖模式

             

               是否兼容

             

            當(dāng)前鎖模式

            X

            IX

            S

            IS

            X

            沖突

            沖突

            沖突

            沖突

            IX

            沖突

            兼容

            沖突

            兼容

            S

            沖突

            沖突

            兼容

            兼容

            IS

            沖突

            兼容

            兼容

            兼容

            如果一個事務(wù)請求的鎖模式與當(dāng)前的鎖兼容,InnoDB就將請求的鎖授予該事務(wù);反之,如果兩者不兼容,該事務(wù)就要等待鎖釋放。

            意向鎖是InnoDB自動加的,不需用戶干預(yù)。對于UPDATE、DELETE和INSERT語句,InnoDB會自動給涉及數(shù)據(jù)集加排他鎖(X);對于普通SELECT語句,InnoDB不會加任何鎖;事務(wù)可以通過以下語句顯示給記錄集加共享鎖或排他鎖。

            ·共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。

            ·排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE。

            用SELECT ... IN SHARE MODE獲得共享鎖,主要用在需要數(shù)據(jù)依存關(guān)系時來確認某行記錄是否存在,并確保沒有人對這個記錄進行UPDATE或者DELETE操作。但是如果當(dāng)前事務(wù)也需要對該記錄進行更新操作,則很有可能造成死鎖,對于鎖定行記錄后需要進行更新操作的應(yīng)用,應(yīng)該使用SELECT... FOR UPDATE方式獲得排他鎖。

            在如表20-7所示的例子中,使用了SELECT ... IN SHARE MODE加鎖后再更新記錄,看看會出現(xiàn)什么情況,其中actor表的actor_id字段為主鍵。

            表20-7           InnoDB存儲引擎的共享鎖例子

            session_1

            session_2

            mysql> set autocommit = 0;

            Query OK, 0 rows affected (0.00 sec)

             

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178;

            +----------+------------+-----------+

            | actor_id | first_name | last_name |

            +----------+------------+-----------+

            | 178      | LISA       | MONROE   |

            +----------+------------+-----------+

            1 row in set (0.00 sec)

            mysql> set autocommit = 0;

            Query OK, 0 rows affected (0.00 sec)

             

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178;

            +----------+------------+-----------+

            | actor_id | first_name | last_name |

            +----------+------------+-----------+

            | 178      | LISA       | MONROE   |

            +----------+------------+-----------+

            1 row in set (0.00 sec)

            當(dāng)前session對actor_id=178的記錄加share mode 的共享鎖:

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178 lock in share mode;

            +----------+------------+-----------+

            | actor_id | first_name | last_name |

            +----------+------------+-----------+

            | 178      | LISA       | MONROE   |

            +----------+------------+-----------+

            1 row in set (0.01 sec)

             

             

            其他session仍然可以查詢記錄,并也可以對該記錄加share mode的共享鎖:

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178 lock in share mode;

            +----------+------------+-----------+

            | actor_id | first_name | last_name |

            +----------+------------+-----------+

            | 178      | LISA       | MONROE   |

            +----------+------------+-----------+

            1 row in set (0.01 sec)

            當(dāng)前session對鎖定的記錄進行更新操作,等待鎖:

            mysql> update actor set last_name = 'MONROE T' where actor_id = 178;

            等待

             

             

            其他session也對該記錄進行更新操作,則會導(dǎo)致死鎖退出:

            mysql> update actor set last_name = 'MONROE T' where actor_id = 178;

            ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

            獲得鎖后,可以成功更新:

            mysql> update actor set last_name = 'MONROE T' where actor_id = 178;

            Query OK, 1 row affected (17.67 sec)

            Rows matched: 1  Changed: 1 Warnings: 0

             

            當(dāng)使用SELECT...FOR UPDATE加鎖后再更新記錄,出現(xiàn)如表20-8所示的情況。

            表20-8             InnoDB存儲引擎的排他鎖例子

            session_1

            session_2

            mysql> set autocommit = 0;

            Query OK, 0 rows affected (0.00 sec)

             

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178;

            +----------+------------+-----------+

            | actor_id | first_name | last_name |

            +----------+------------+-----------+

            | 178      | LISA       | MONROE   |

            +----------+------------+-----------+

            1 row in set (0.00 sec)

            mysql> set autocommit = 0;

            Query OK, 0 rows affected (0.00 sec)

             

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178;

            +----------+------------+-----------+

            | actor_id | first_name | last_name |

            +----------+------------+-----------+

            | 178      | LISA       | MONROE   |

            +----------+------------+-----------+

            1 row in set (0.00 sec)

            當(dāng)前session對actor_id=178的記錄加for update的共享鎖:

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178 for update;

            +----------+------------+-----------+

            | actor_id | first_name | last_name |

            +----------+------------+-----------+

            | 178      | LISA       | MONROE   |

            +----------+------------+-----------+

            1 row in set (0.00 sec)

             

             

            其他session可以查詢該記錄,但是不能對該記錄加共享鎖,會等待獲得鎖:

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178;

            +----------+------------+-----------+

            | actor_id | first_name | last_name |

            +----------+------------+-----------+

            | 178      | LISA       | MONROE   |

            +----------+------------+-----------+

            1 row in set (0.00 sec)

             

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178 for update;

            等待

            當(dāng)前session可以對鎖定的記錄進行更新操作,更新后釋放鎖:

            mysql> update actor set last_name = 'MONROE T' where actor_id = 178;

            Query OK, 1 row affected (0.00 sec)

            Rows matched: 1  Changed: 1 Warnings: 0

             

            mysql> commit;

            Query OK, 0 rows affected (0.01 sec)

             

             

            其他session獲得鎖,得到其他session提交的記錄:

            mysql> select actor_id,first_name,last_name from actor where actor_id = 178 for update;

            +----------+------------+-----------+

            | actor_id | first_name | last_name |

            +----------+------------+-----------+

            | 178      | LISA       | MONROE T |

            +----------+------------+-----------+

            1 row in set (9.59 sec)

             

             20.3.4 InnoDB行鎖實現(xiàn)方式

            InnoDB行鎖是通過給索引上的索引項加鎖來實現(xiàn)的,這一點MySQL與Oracle不同,后者是通過在數(shù)據(jù)塊中對相應(yīng)數(shù)據(jù)行加鎖來實現(xiàn)的。InnoDB這種行鎖實現(xiàn)特點意味著:只有通過索引條件檢索數(shù)據(jù),InnoDB才使用行級鎖,否則,InnoDB將使用表鎖!

            在實際應(yīng)用中,要特別注意InnoDB行鎖的這一特性,不然的話,可能導(dǎo)致大量的鎖沖突,從而影響并發(fā)性能。下面通過一些實際例子來加以說明。

            (1)在不通過索引條件查詢的時候,InnoDB確實使用的是表鎖,而不是行鎖。

            在如表20-9所示的例子中,開始tab_no_index表沒有索引:

            mysql> create table tab_no_index(id int,name varchar(10)) engine=innodb;
            Query OK, 0 rows affected (0.15 sec)
            mysql> insert into tab_no_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
            Query OK, 4 rows affected (0.00 sec)
            Records: 4  Duplicates: 0  Warnings: 0

            表20-9         InnoDB存儲引擎的表在不使用索引時使用表鎖例子

            session_1

            session_2

            mysql> set autocommit=0;

            Query OK, 0 rows affected (0.00 sec)

            mysql> select * from tab_no_index where id = 1 ;

            +------+------+

            | id   | name |

            +------+------+

            | 1    | 1    |

            +------+------+

            1 row in set (0.00 sec)

            mysql> set autocommit=0;

            Query OK, 0 rows affected (0.00 sec)

            mysql> select * from tab_no_index where id = 2 ;

            +------+------+

            | id   | name |

            +------+------+

            | 2    | 2    |

            +------+------+

            1 row in set (0.00 sec)

            mysql> select * from tab_no_index where id = 1 for update;

            +------+------+

            | id   | name |

            +------+------+

            | 1    | 1    |

            +------+------+

            1 row in set (0.00 sec)

             

             

            mysql> select * from tab_no_index where id = 2 for update;

            等待

            在如表20-9所示的例子中,看起來session_1只給一行加了排他鎖,但session_2在請求其他行的排他鎖時,卻出現(xiàn)了鎖等待!原因就是在沒有索引的情況下,InnoDB只能使用表鎖。當(dāng)我們給其增加一個索引后,InnoDB就只鎖定了符合條件的行,如表20-10所示。

            創(chuàng)建tab_with_index表,id字段有普通索引:

            mysql> create table tab_with_index(id int,name varchar(10)) engine=innodb;
            Query OK, 0 rows affected (0.15 sec)
            mysql> alter table tab_with_index add index id(id);
            Query OK, 4 rows affected (0.24 sec)
            Records: 4  Duplicates: 0  Warnings: 0

            表20-10    InnoDB存儲引擎的表在使用索引時使用行鎖例子

            session_1

            session_2

            mysql> set autocommit=0;

            Query OK, 0 rows affected (0.00 sec)

            mysql> select * from tab_with_index where id = 1 ;

            +------+------+

            | id   | name |

            +------+------+

            | 1    | 1    |

            +------+------+

            1 row in set (0.00 sec)

            mysql> set autocommit=0;

            Query OK, 0 rows affected (0.00 sec)

            mysql> select * from tab_with_index where id = 2 ;

            +------+------+

            | id   | name |

            +------+------+

            | 2    | 2    |

            +------+------+

            1 row in set (0.00 sec)

            mysql> select * from tab_with_index where id = 1 for update;

            +------+------+

            | id   | name |

            +------+------+

            | 1    | 1    |

            +------+------+

            1 row in set (0.00 sec)

             

             

            mysql> select * from tab_with_index where id = 2 for update;

            +------+------+

            | id   | name |

            +------+------+

            | 2    | 2    |

            +------+------+

            1 row in set (0.00 sec)

            (2)由于MySQL的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是如果是使用相同的索引鍵,是會出現(xiàn)鎖沖突的。應(yīng)用設(shè)計的時候要注意這一點。

            在如表20-11所示的例子中,表tab_with_index的id字段有索引,name字段沒有索引:

            mysql> alter table tab_with_index drop index name;
            Query OK, 4 rows affected (0.22 sec)
            Records: 4  Duplicates: 0  Warnings: 0
            mysql> insert into tab_with_index  values(1,'4');
            Query OK, 1 row affected (0.00 sec)
            mysql> select * from tab_with_index where id = 1;
            +------+------+
            | id   | name |
            +------+------+
            | 1    | 1    |
            | 1    | 4    |
            +------+------+
            2 rows in set (0.00 sec)

            表20-11    InnoDB存儲引擎使用相同索引鍵的阻塞例子

            session_1

            session_2

            mysql> set autocommit=0;

            Query OK, 0 rows affected (0.00 sec)

            mysql> set autocommit=0;

            Query OK, 0 rows affected (0.00 sec)

            mysql> select * from tab_with_index where id = 1 and name = '1' for update;

            +------+------+

            | id   | name |

            +------+------+

            | 1    | 1    |

            +------+------+

            1 row in set (0.00 sec)

             

             

            雖然session_2訪問的是和session_1不同的記錄,但是因為使用了相同的索引,所以需要等待鎖:

            mysql> select * from tab_with_index where id = 1 and name = '4' for update;

            等待

            (3)當(dāng)表有多個索引的時候,不同的事務(wù)可以使用不同的索引鎖定不同的行,另外,不論是使用主鍵索引、唯一索引或普通索引,InnoDB都會使用行鎖來對數(shù)據(jù)加鎖。

            在如表20-12所示的例子中,表tab_with_index的id字段有主鍵索引,name字段有普通索引:

            mysql> alter table tab_with_index add index name(name);
            Query OK, 5 rows affected (0.23 sec)
            Records: 5  Duplicates: 0  Warnings: 0

            表20-12    InnoDB存儲引擎的表使用不同索引的阻塞例子

            ·          session_1

            ·          session_2

            mysql> set autocommit=0;

            Query OK, 0 rows affected (0.00 sec)

            mysql> set autocommit=0;

            Query OK, 0 rows affected (0.00 sec)

            mysql> select * from tab_with_index where id = 1 for update;

            +------+------+

            | id   | name |

            +------+------+

            | 1    | 1    |

            | 1    | 4    |

            +------+------+

            2 rows in set (0.00 sec)

             

             

            Session_2使用name的索引訪問記錄,因為記錄沒有被索引,所以可以獲得鎖:

            mysql> select * from tab_with_index where name = '2' for update;

            +------+------+

            | id   | name |

            +------+------+

            | 2    | 2    |

            +------+------+

            1 row in set (0.00 sec)

             

            由于訪問的記錄已經(jīng)被session_1鎖定,所以等待獲得鎖。:

            mysql> select * from tab_with_index where name = '4' for update;

            (4)即便在條件中使用了索引字段,但是否使用索引來檢索數(shù)據(jù)是由MySQL通過判斷不同執(zhí)行計劃的代價來決定的,如果MySQL認為全表掃描效率更高,比如對一些很小的表,它就不會使用索引,這種情況下InnoDB將使用表鎖,而不是行鎖。因此,在分析鎖沖突時,別忘了檢查SQL的執(zhí)行計劃,以確認是否真正使用了索引。關(guān)于MySQL在什么情況下不使用索引的詳細討論,參見本章“索引問題”一節(jié)的介紹。

            在下面的例子中,檢索值的數(shù)據(jù)類型與索引字段不同,雖然MySQL能夠進行數(shù)據(jù)類型轉(zhuǎn)換,但卻不會使用索引,從而導(dǎo)致InnoDB使用表鎖。通過用explain檢查兩條SQL的執(zhí)行計劃,我們可以清楚地看到了這一點。

            例子中tab_with_index表的name字段有索引,但是name字段是varchar類型的,如果where條件中不是和varchar類型進行比較,則會對name進行類型轉(zhuǎn)換,而執(zhí)行的全表掃描。

            mysql> alter table tab_no_index add index name(name);
            Query OK, 4 rows affected (8.06 sec)
            Records: 4  Duplicates: 0  Warnings: 0
            mysql> explain select * from tab_with_index where name = 1 \G
            *************************** 1. row ***************************
            id: 1
            select_type: SIMPLE
            table: tab_with_index
            type: ALL
            possible_keys: name
            key: NULL
            key_len: NULL
            ref: NULL
            rows: 4
            Extra: Using where
            1 row in set (0.00 sec)
            mysql> explain select * from tab_with_index where name = '1' \G
            *************************** 1. row ***************************
            id: 1
            select_type: SIMPLE
            table: tab_with_index
            type: ref
            possible_keys: name
            key: name
            key_len: 23
            ref: const
            rows: 1
            Extra: Using where
            1 row in set (0.00 sec)

            標(biāo)簽: Mysql事務(wù)
            轉(zhuǎn)自:
            http://www.cnblogs.com/zhizhesky/articles/2164089.html
            posted on 2012-10-15 11:59 會飛的兔子 閱讀(468) 評論(0)  編輯 收藏 引用 所屬分類: 數(shù)據(jù)庫,MIS系統(tǒng)
            精品久久久久成人码免费动漫| 青青青青久久精品国产 | 伊人久久综在合线亚洲2019| 亚洲欧美成人久久综合中文网| 香港aa三级久久三级老师2021国产三级精品三级在 | 久久久久久久99精品免费观看| 国产成人精品免费久久久久| 久久久久久久综合日本亚洲| 亚洲精品国产第一综合99久久| 人妻精品久久无码区| 久久久噜噜噜久久| 久久精品国产亚洲精品2020| 人妻系列无码专区久久五月天| 人妻无码αv中文字幕久久琪琪布| 岛国搬运www久久| av国内精品久久久久影院| 一级a性色生活片久久无| 久久久久国产一级毛片高清版| 狠狠色婷婷久久综合频道日韩| 久久久艹| 亚洲一区中文字幕久久| 久久香蕉国产线看观看精品yw | 好久久免费视频高清| 久久亚洲AV无码精品色午夜| 日韩精品国产自在久久现线拍| 超级97碰碰碰碰久久久久最新 | 久久成人永久免费播放| 久久精品国产清高在天天线| 国产免费久久精品99re丫y| 久久国产V一级毛多内射| 久久综合九色综合精品| 精品国产乱码久久久久久郑州公司| 久久婷婷色香五月综合激情| 久久久精品久久久久久| 国产精品欧美久久久久天天影视| 久久中文娱乐网| 精品久久久久久99人妻| 久久精品国产精品亚洲艾草网美妙| 国产成人精品久久亚洲| 999久久久免费国产精品播放| 成人免费网站久久久|