MYSQL INNODB 鎖表小研究

表結構以下:php

delimiter $$mysql

CREATE TABLE `wrox_shop_order` (
`o_id` int(11) NOT NULL AUTO_INCREMENT,
`order_date` datetime DEFAULT NULL,
`order_status` varchar(45) DEFAULT 'CREATED',
`customer_id` int(11) DEFAULT NULL,
PRIMARY KEY (`o_id`),
KEY `orderDate` (`order_date`) //這裏最開始不加,後面添上的
) ENGINE=InnoDB AUTO_INCREMENT=164 DEFAULT CHARSET=utf8$$sql

 

這樣一個數據表:數據庫

開啓兩個mysql客戶端:工具

由於工做須要 我在mysql workbench裏面用了一個 存儲過程,相對簡單的一個:
delimiter $$
/××
××
param1 表示輸入的值,param2,param3 是輸出變量:後面使用
××select @m1 as a,@m2 as b; 能夠獲得輸出的值
××/
CREATE PROCEDURE last_delete_info (IN param1 datetime,OUT param2 INT,OUT param3 varchar(45))
BEGIN
   select o_id,order_status into param2,param3 from wrox_shop_order where order_date=param1 limit 1 for update;
   #delete from wrox_shop_order where o_id=param2; //這一行後面用@DELETE來表示
END
$$
delimiter ;

首先在workBench裏執行:測試

操做一:spa

set autocommit=0;
call last_delete_info(
'2013-04-01 19:49:58',@m1,@m2); select @m1 as a,@m2 as b;

結果:

此時 o_id 爲3的行是否被鎖住了呢?打開mysql 命令行到相應數據庫中執行:命令行

操做二:code

delete from wrox_shop_order where o_id=3;blog

結果刪除不了數據,說明該行數據被加了鎖,那麼刪除其餘數據呢?

delete from wrox_shop_order where o_id=4 or o_id=5; 

結果仍是刪除不了數據,

從這裏咱們驗證了不少人都驗證的問題,若是innodb 沒有在加索引的行上加鎖,那麼會使用表鎖

 

接下來若是有注意最開始的建立語句有這麼一個:KEY `orderDate` (`order_date`) //這裏最開始不加,後面添上的

那麼如今去個order_date加個索引:

一個小提示:如今autocomint=0;直接改的話是改不了的。須要commint 後才能夠加索引;而後執行:

ALTER TABLE `test`.`wrox_shop_order` 
ADD INDEX `order_date` (`order_date` ASC) ;

而後從新執行上面兩個mysql客戶端工具的操做,執行到第二步的時候命令行仍是沒法刪除,可是若是刪除其餘數據倒是能夠的

說明INNODB在加了索引的的行上加鎖是加的行級鎖,並且是對索引加的鎖

今天又作了一些測試,再次總結一下:

好比:

 

delimiter $$

CREATE TABLE `akulubala` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `artist` varchar(100) NOT NULL,
  `title` varchar(100) NOT NULL,
  `index_column` tinyint,
  PRIMARY KEY (`id`),
  KEY `index_c` (`index_column`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8$$

 

執行:

set autocommit=0;

SELECT * FROM akulubala.akulubala where index_column=9 for update;

 

另一個進程執行:

  1. SELECT * FROM akulubala.akulubala where index_column=9 for update; 這裏會出現等待。需等待第一個進程commit;
  2. update akulubala set title='s' where index_column=?; 這裏無論ID !=9 就能夠執行  (說明索引被加了鎖)
  3.  update akulubala set artist = 'aaaaa' where id = 4;這裏 只要ID 行沒有在前一個進程搜索的結果中 就不會等待 

    由以上三點能夠得出鎖是對索引的鎖,即對索引加鎖,使用被加鎖的索引時都會等待,而且對由索引查出的行加鎖,若是更新數據沒有用到任何索引,就會全表加鎖..

 

  1. update akulubala set artist='ttt' where id=3;若是id=3不在前一個進程的查詢結果中就 能夠執行;
  2. 單純的查詢如select * from akulubala 是查出全部數據

 

 

  另外:事務和鎖是兩回事,事務有四個隔離級別,不一樣的隔離級別有不一樣的鎖定機制:INNODB 默認是可重複讀
  • 未提交讀(Read Uncommitted):容許髒讀,也就是可能讀取到其餘會話中未提交事務修改的數據
  • 提交讀(Read Committed):只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別
  • 可重複讀(Repeated Read):可重複讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB默認級別。在SQL標準中,該隔離級別消除了不可重複讀,可是還存在幻象讀
  • 串行讀(Serializable):徹底串行化的讀,每次讀都須要得到表級共享鎖,讀寫相互都會阻塞
相關文章
相關標籤/搜索