九、MySQL中锁机制

1、应用场合

比如有如下操作:

(1)从数据库中取出id的值(比如id=100)

(2)把这个值-1(id=100-1)

(3)再把该值存回到数据库(id=99)

假如有两个进程(用户)同时操作,

使用锁机制来完成,同时操作时,只有一个进程获得锁,其他进程就等待,

进程1 进程2
添加锁 wating等待
id =100 wating等待
id=100-1 wating等待
id=99 wating等待
释放锁 id =100
id=100-1
id=99

2、mysql里面的锁的几种形式

锁机制:

当客户端操作表(记录)时,为了保证操作的隔离性(多个客户端操作不能相互影响),通过加锁来处理。

1、操作方面:

读锁:读操作时增加的锁,也叫共享锁,S-lock。

特征是所有人都只可以读,只有释放锁之后才可以写。

写锁:写操作时增加的锁,也叫独占锁或排他锁,X-lock。

特征,只有锁表的客户可以操作(读写)这个表,其他客户读都不能读。

2、锁定粒度(范围)

表级锁:开销小,加锁快,发生锁冲突的概率最高,并发度最低。

myisam引擎的表支持表锁,

行级锁:开销大,加锁慢,发生锁冲突的概率最低,并发度也最高。

innodb引擎的表支持行锁与表锁。

3、语法

  1. -- 添加锁:
  2. lock table 表名1 read|write,表名2 read|write
  3. -- 释放锁:
  4. unlock tables

3、表锁的演示

建立测试表,并添加测试数据:

  1. create table user(
  2. id int primary key auto_increment,
  3. name varchar(32) not null default '',
  4. age tinyint unsigned not null default 0,
  5. email varchar(32) not null default '',
  6. classid int not null default 1
  7. )engine myisam charset utf8;
  8. insert into user values(null,'xiaogang',12,'gang@sohu.com',4),
  9. (null,'xiaohong',13,'hong@sohu.com',2),
  10. (null,'xiaolong',31,'long@sohu.com',2),
  11. (null,'xiaofeng',22,'feng@sohu.com',3),
  12. (null,'xiaogui',42,'gui@sohu.com',3);

1、添加读锁

锁 - 图1

另外一个用户登录后,不能执行修改操作,可以执行查询操作。

锁 - 图2

注意:添加读锁后,自己和其他的进程(用户)只能对该表查询操作,自己也不能执行修改操作。

锁 - 图3

注意:添加表的锁定后,针对锁表的用户,只能操作锁定的表,不能操作没有锁定的表。

锁 - 图4

执行释放锁,

锁 - 图5

释放锁之后,另外的一个进程,可以执行修改的操作了。

锁 - 图6

2、添加写锁

只有锁表的客户可以操作(读写)这个表,其他客户读都不能读。

锁 - 图7

其他的用户,读都不能读,

锁 - 图8

4、行锁的演示

innodb存储引擎是通过给索引上的索引项加锁来实现的,

这就意味着:只有通过索引条件(主键)检索数据,innodb才会使用行级锁,否则,innodb使用表锁。

锁 - 图9

语法:

  1. begin;
  2. 执行语句;
  3. commit;

当前用户添加行锁,另外的一个用户登录,进行操作。

锁 - 图10

5、通过php代码来实现锁机制

在apache里面有一个bin目录 下面有一个ab.exe工具,该工具可以模拟多个并发测试。

锁 - 图11

语法:

  1. ab.exe n 总的请求数 -c 并发数 url地址;

(1)创建一个表,表里面就只有一个字段,便于我们演示

锁 - 图12

(2)通过代码来完成,

从数据库中取出id的值(比如id=100)

把这个值+1(id=100+1)

再把该值存回到数据库(id=101)

(3)使用ab工具模拟并发操作。

锁 - 图13

查看表里面的id的值,我们执行了代码50次,应该id的值是150才对,则说明我们请求的50个并发,有几个并发是同时执行的。

锁 - 图14

(4)添加锁机制来进行测试。

把表里面的数据, 再改为100;

锁 - 图15

修改如下代码,添加锁机制

锁 - 图16

开始执行50个并发

锁 - 图17

测试效果如下;

锁 - 图18

2、使用mysql里面锁机制缺点

就是阻塞,假如有一张goods表,goods表里面有一个库存的字段,当前下订单时,如果锁定了goods表,还能执行查询goods表吗?

会阻塞拖慢整个网站的速度,一但锁定goods表(添加写锁,要更改库存),则其他进程就无法查询goods表。

3、可以使用文件锁

锁 - 图19

锁 - 图20

  1. error_reporting(0);
  2. $conn = mysql_connect('localhost','root','root');
  3. mysql_query('use demo');
  4. mysql_query('set names utf8');
  5. //打开该文件
  6. $fh = fopen('./lock.txt','w');
  7. //添加锁
  8. flock($fh,LOCK_EX );
  9. //mysql_query('lock table a write');//添加写锁
  10. //取出id的值
  11. $res = mysql_query('select id from a');
  12. $row = mysql_fetch_assoc($res);
  13. $id = $row['id'];
  14. //执行该id+1运算
  15. $id = $id+1;
  16. //执行结果,再写入数据库
  17. mysql_query("update a set id = $id");
  18. //释放锁
  19. flock($fh,LOCK_UN );
  20. //mysql_query('unlock tables');

锁 - 图21