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):彻底串行化的读,每次读都须要得到表级共享锁,读写相互都会阻塞
相关文章
相关标签/搜索