隔离级别研究: http://www.cnblogs.com/JohnABC/p/3521061.html

表级:引擎 MyISAM, 理解为锁住整个表, 锁定期间, 其它进程无法对该表进行写操作, 如果是读锁, 其他进程可以同时读, 如果是写锁, 则其它进程则读也不允许

行级:引擎 INNODB, 单独的一行记录加锁, 其它进程还是可以对同一个表中的其它记录进行操作

页级:引擎 BDB, 表级锁速度快, 但冲突多, 行级冲突少, 但速度慢, 页级折衷, 一次锁定相邻的一组记录

表级锁:开销小, 加锁快, 不会出现死锁, 锁定粒度大, 发生锁冲突的概率最高, 并发度最低

行级锁:开销大, 加锁慢, 会出现死锁, 锁定粒度最小, 发生锁冲突的概率最低, 并发度也最高

页面锁:开销和加锁时间界于表锁和行锁之间, 会出现死锁, 锁定粒度界于表锁和行锁之间, 并发度一般

表锁

MyISAM在执行查询语句(SELECT)前, 会自动给涉及的所有表加读锁, 在执行更新操作(UPDATE、DELETE、INSERT等)前, 会自动给涉及的表加写锁, 这个过程并不需要用户干预, 因此, 用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁

表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)

对WRITE, MySQL使用的表锁定方法原理如下:如果在表上没有锁, 在它上面放一个写锁, 否则, 把锁定请求放在写锁定队列中

对READ, MySQL使用的表锁方法原理如下:如果在表上没有写锁定, 把一个读锁定放在它上面否则, 把锁请求放在读锁定队列中

LOCK TABLE `TNAME` READ|WRITE

行锁

在SQL语句处理期间, InnoDB自动获得行锁定和BDB获得页锁定, 而不是在事务启动时获得

InnoDB行锁是通过给索引项加锁来实现的, 即只有通过索引条件检索数据, InnoDB才使用行级锁, 否则将使用表锁!

行锁是建立在索引上的!!所以如果给一个unique列加锁, 先在unique对应的记录上加索引, 然后找到对应的主键索引记录, 加上锁

行级锁定的优点:

  当在许多线程中访问不同的行时只存在少量锁定冲突

  回滚时只有少量的更改

  可以长时间锁定单一的行

行级锁定的缺点:

  比页级或表级锁定占用更多的内存

  当在表的大部分中使用时, 比页级或表级锁定速度慢, 因为你必须获取更多的锁(比如UPDATE多条数据)

  如果你在大部分数据上经常进行GROUP BY操作或者必须经常扫描整个表, 比其它锁定明显慢很多

  用高级别锁定, 通过支持不同的类型锁定, 你也可以很容易地调节应用程序, 因为其锁成本小于行级锁定

SELECT ... LOCK IN SHARE MODE 加S锁
SELECT ... FOR UPDATE 加X锁

快照读:简单的select操作, 属于快照读, 不加锁 (当然, 也有例外)

select * from table where ?;

当前读:特殊的读操作, 插入/更新/删除操作, 属于当前读, 需要加锁

select * from table where ? lock in share mode;

select * from table where ? for update;

insert into table values (…);

update table set ? where ?;

delete from table where ?;

可以看看加锁处理分析http://hedengcheng.com/?p=771或者百度网盘http://pan.baidu.com/s/1mgN00Og

在以下情况下, 表锁定优先于页级或行级锁定:

  表的大部分语句用于读取

  对严格的关键字进行读取和更新, 你可以更新或删除可以用单一的读取的关键字来提取的一行:

    UPDATE tbl_name SET column=value WHERE unique_key_col=key_value

    DELETE FROM tbl_name WHERE unique_key_col=key_value

  SELECT 结合并行的INSERT语句, 并且只有很少的UPDATE或DELETE语句

  在整个表上有许多扫描或GROUP BY操作, 没有任何写操作

如果想要在一个表上做大量的 INSERT 和 SELECT 操作, 但是并行的插入却不可能时, 可以将记录插入到临时表中, 然后定期将临时表中的数据更新到实际的表里, 可以用以下命令实现:

mysql> LOCK TABLES real_table WRITE, insert_table WRITE;
mysql> INSERT INTO real_table SELECT * FROM insert_table;
mysql> TRUNCATE TABLE insert_table;
mysql> UNLOCK TABLES;

MyISAM

  但在一定条件下MyISAM表也支持查询和插入的操作的并发进行, 其机制是通过控制一个系统变量(concurrent_insert)来进行的, 当其值设置为0时, 不允许并发插入, 当其值设置为1 时, 如果MyISAM表中没有空洞(即表中没有被删除的行), MyISAM允许在一个进程读表的同时, 另一个进程从表尾插入记录, 当其值设置为2时, 无论 MyISAM 表中有没有空洞, 都允许在表尾并发插入记录(只能插入操作)

  MyISAM锁调度是如何实现的呢, 这也是一个很关键的问题, 例如, 当一个进程请求某个MyISAM表的读锁, 同时另一个进程也请求同一表的写锁, 此时 MySQL将会如优先处理进程呢?通过研究表明, 写进程将先获得锁(即使读请求先到锁等待队列), 但这也造成一个很大的缺陷, 即大量的写操作会造成查询操作很难获得读锁, 从而可能造成永远阻塞, 所幸我们可以通过一些设置来调节MyISAM的调度行为, 我们可通过指定参数low-priority-updates, 使MyISAM默认引擎给予读请求以优先的权利, 设置其值为1(set low_priority_updates=1), 使优先级降低

  执行LOCK TABLES后, 只能访问显式加锁的这些表, 不能访问未加锁的表

InnoDB

  由于InnoDB预设是Row-Level Lock, 所以只有「明确」的指定主键, MySQL才会执行Row lock (只锁住被选取的资料例), 否则MySQL将会执行Table Lock (将整个资料表单给锁住)

举个例子: 假设有个表单products, 里面有id跟name二个栏位, id是主键

例1: (明确指定主键, 并且有此笔资料, row lock)

SELECT * FROM products WHERE id='' FOR UPDATE;
SELECT * FROM products WHERE id='' and type=1 FOR UPDATE;

例2: (明确指定主键, 若查无此笔资料, 无lock)

SELECT * FROM products WHERE id='-1' FOR UPDATE;

例3: (无主键, table lock)

SELECT * FROM products WHERE name='Mouse' FOR UPDATE;

例4: (主键不明确, table lock)

SELECT * FROM products WHERE id<>'' FOR UPDATE;

例5: (主键不明确, table lock)

SELECT * FROM products WHERE id LIKE '' FOR UPDATE;

注1: FOR UPDATE仅适用于InnoDB, 且必须在交易区块(BEGIN/COMMIT)中才能生效, 此时其他事务不能修改此数据!!!!!!

注2: 要测试锁定的状况, 可以利用MySQL的Command Mode, 开二个视窗来做测试

在MySql 5.0中测试确实是这样的

添加了(行级锁/表级锁)锁的数据不能被其它事务再锁定, 也不被其它事务修改(修改、删除)是表级锁时, 不管是否查询到记录, 都会锁定表;

如果A与B都对表id进行查询但查询不到记录, 则A与B在查询上不会进行row锁, 但A与B都会获取排它锁, 此时A再插入一条记录的话则会因为B已经有锁而处于等待中, 此时B再插入一条同样的数据则会抛出Deadlock found when trying to get lock; try restarting transaction然后释放锁, 此时A就获得了锁而插入成功

锁测试

  MyISAM 查询表级锁争用情况(Table_locks_waited的值比较高, 说明存在着较严重的表级锁争用情况)

mysql> show status like ‘table%’;
+-----------------------+----------+
| Variable_name | Value |
+-----------------------+----------+
| Table_locks_immediate | 76939364 |
| Table_locks_waited | 305089 |
+-----------------------+----------+
2 rows in set (0.00 sec)

  MyISAM长时间读, 测试写操作等待(客户端1进行一个比较长时间的读操作时, 分别用客户端2进行读和写操作)

  client 1

mysql>select count(*) from gz_phone group by ua;
75508 rows in set (3 min 15.87 sec)

  client 2

    select id,phone from gz_phone limit 1000,10;
+------+-------+
| id | phone |
+------+-------+
| 1001 | 2222 |
| 1002 | 2222 |
| 1003 | 2222 |
| 1004 | 2222 |
| 1005 | 2222 |
| 1006 | 2222 |
| 1007 | 2222 |
| 1008 | 2222 |
| 1009 | 2222 |
| 1010 | 2222 |
+------+-------+
10 rows in set (0.01 sec) mysql> update gz_phone set phone=’11111111111′ where id=1001;
Query OK, 0 rows affected (2 min 57.88 sec)
Rows matched: 1 Changed: 0 Warnings: 0

  说明当数据表有一个读锁时, 其它进程的查询操作可以马上执行, 但更新操作需等待读锁释放后才会执行

  MyISAM长时间写, 测试读操作等待(客户端1进行一个比较长时间的写操作时, 分别用客户端2, 3进行读和写操作)

  client 1

mysql> update gz_phone set phone=’11111111111′;
Query OK, 1671823 rows affected (3 min 4.03 sec)
Rows matched: 2212070 Changed: 1671823 Warnings: 0

  client 2

mysql> select id,phone,ua,day from gz_phone limit 10;
+----+-------+-------------------+------------+
| id | phone | ua | day |
+----+-------+-------------------+------------+
| 1 | 2222 | SonyEricssonK310c | 2007-12-19 |
| 2 | 2222 | SonyEricssonK750c | 2007-12-19 |
| 3 | 2222 | MAUI WAP Browser | 2007-12-19 |
| 4 | 2222 | Nokia3108 | 2007-12-19 |
| 5 | 2222 | LENOVO-I750 | 2007-12-19 |
| 6 | 2222 | BIRD_D636 | 2007-12-19 |
| 7 | 2222 | SonyEricssonS500c | 2007-12-19 |
| 8 | 2222 | SAMSUNG-SGH-E258 | 2007-12-19 |
| 9 | 2222 | NokiaN73-1 | 2007-12-19 |
| 10 | 2222 | Nokia2610 | 2007-12-19 |
+----+-------+-------------------+------------+
10 rows in set (2 min 58.56 sec)

  client 3

mysql> update gz_phone set phone=’55555′ where id=1;
Query OK, 1 row affected (3 min 50.16 sec)
Rows matched: 1 Changed: 1 Warnings: 0

  说明当数据表有一个写锁时, 其它进程的读写操作都需等待读锁释放后才会执行

  InnoDB FOR UPDATE 测试(client1 执行select for update后不提交, client 2执行读写操作)

CREATE TABLE ·user`(
id int primary key auto_increment,
num int
) TYPE=INNODB; INSERT INTO `user` values(1, 1);
INSERT INTO `user` values(2, 2);

  client 1

SET autocommit = 0;
SELECT * FROM `user` WHERE `id`=1 FOR UPDATE;

  client 2

mysql>SET autocommit = 0;
mysql>SELECT * FROM `user` WHERE `id`=1;
+----+-----+
| id | num |
+----+-----+
| 1 | 1 |
+----+-----+
1 row in set (0.00 sec)
mysql>UDPATE `user` SET `num`=2 WHERE `id`=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>SELECT * FROM `user` WHERE `id`=1 FOR UPDATE;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>UPDATE `user` SET num=3 WHERE `id`=2;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0

  有此看出使用FOR UPDATE锁定一条记录时, 此记录另一个事务只可读, 不可修改, 其他记录可以任意进行读取和修改

MySQL-锁研究的更多相关文章

  1. MySql InnoDB中的锁研究

    # MySql InnoDB中的锁研究 ## 1.InnoDB中有哪些锁### 1. 共享和排他(独占)锁(Shared and Exclusive Locks) InnoDB实现标准的行级锁定,其中 ...

  2. MySQL锁之三:MySQL的共享锁与排它锁编码演示

    一.行锁之MySQL  使用SELECT ... FOR UPDATE 做事务写入前的确认 以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEA ...

  3. mysql锁简谈

    1.mysql锁, 作用:解决因资源共享而造成的并发问题. 实例:买最好一件衣服X A: X 买: X加锁----->试衣服……下单……付款……打包….------>X解锁 B: X 买: ...

  4. MySQL 锁(完整版)

    目录 锁总览 锁的作用 加锁流程 锁对数据库的影响 锁等待 死锁 锁类型 锁范围 锁方式 全局锁 全局读锁 全局QC锁 QC锁存在的问题: 备份锁 backup lock MDL锁 MDL锁类型 MD ...

  5. mysql锁

    锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数 ...

  6. Mysql锁初步

    存储引擎 要了解mysql的锁,就要先从存储引擎说起. 常用存储引擎列表如下图所示: 最常使用的两种存储引擎: Myisam是Mysql的默认存储引擎.当create创建新表时,未指定新表的存储引擎时 ...

  7. mysql锁表机制及相关优化

    (该文章为方便自己查阅,也希望对大家有所帮助,转载于互联网) 1. 锁机制 当前MySQL支持 ISAM, MyISAM, MEMORY (HEAP) 类型表的表级锁,BDB 表支持页级锁,InnoD ...

  8. MySQL锁系列3 MDL锁

    http://www.cnblogs.com/xpchild/p/3790139.html   MySQL为了保护数据字典元数据,使用了metadata lock,即MDL锁,保证在并发的情况下,结构 ...

  9. 01 MySQL锁概述

    锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O 等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有 ...

  10. Mysql锁机制介绍

    Mysql锁机制介绍 一.概况MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking ...

随机推荐

  1. mybatis源码分析(3)-----SqlSessionHolder作用

    1. sqlSessionHolder 是位于mybatis-spring 包下面,他的作用是对于sqlSession和事务的控制 sqlSessionHolder 继承了spring的Resourc ...

  2. When to use static method in a java class

    First , please understand its feature : * no need to instantiate a instance, i.e. simply you can jus ...

  3. nginx出现504 Gateway Time-out的解决思路

    http://www.xbc.me/nginx-fix-504-gateway-timeout/ 在安装完Nginx+PHP-fpm+Mysql后 (如何安装LNMP环境,请参考快速配置LNMP环境N ...

  4. IOS开发自定义CheckBox控件

    IOS本身没有系统的CheckBox组件,但是实际开发中会经常用到,所以专门写了一个CheckBox控件,直接上代码 效果图: UICheckBoxButton.h文件如下: #import #imp ...

  5. oracle定时任务(dbms_job)

    author:skate time:2007-09-12 http://publish.it168.com/2006/0311/20060311017002.shtml 今天总结下Oracle的任务队 ...

  6. 要使用C#实现一个ActiveX控件

    要使用C#实现一个ActiveX控件,需要解决三个问题: 1.使.NET组件能够被COM调用 2.在客户机上注册后,ActiveX控件能通过IE的安全认证 3.未在客户机上注册时,安装包能通过IE的签 ...

  7. Index downloads are disabled, search results may be incomplete.

    20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送) 国内私募机构九鼎控股打造,九鼎投资是在全国股 ...

  8. NAT详解 z

    http://www.cnblogs.com/beginmind/p/6380489.html 1.为什么出现了NAT? IP地址只有32位,最多只有42.9亿个地址,还要去掉保留地址.组播地址,能用 ...

  9. sqlalchemy: TimeoutError: QueuePool limit of size 5 overflow 10 reached, connection timed out, timeout 30

    mysql建立的连接要及时删除,不然连接池资源耗尽 相关文章参考: http://blog.csdn.net/robinson1988/article/details/4713294 http://b ...

  10. CSS:CSS+DIV布局网页

    现代网页布局:CSS+DIV: 一般的网页都是顺序布局的,很难达到我们需要的网页布局格式,此时使用DIV进行分层布局,类似于盒子,对每一部分内容进行设计.这是现在主流的网页布局方式,使用DIV+CSS ...