九、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、语法
-- 添加锁:lock table 表名1 read|write,表名2 read|write-- 释放锁:unlock tables
3、表锁的演示
建立测试表,并添加测试数据:
create table user(id int primary key auto_increment,name varchar(32) not null default '',age tinyint unsigned not null default 0,email varchar(32) not null default '',classid int not null default 1)engine myisam charset utf8;insert into user values(null,'xiaogang',12,'gang@sohu.com',4),(null,'xiaohong',13,'hong@sohu.com',2),(null,'xiaolong',31,'long@sohu.com',2),(null,'xiaofeng',22,'feng@sohu.com',3),(null,'xiaogui',42,'gui@sohu.com',3);
1、添加读锁

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

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

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

执行释放锁,

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

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

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

4、行锁的演示
innodb存储引擎是通过给索引上的索引项加锁来实现的,
这就意味着:只有通过索引条件(主键)检索数据,innodb才会使用行级锁,否则,innodb使用表锁。

语法:
begin;执行语句;commit;
当前用户添加行锁,另外的一个用户登录,进行操作。

5、通过php代码来实现锁机制
在apache里面有一个bin目录 下面有一个ab.exe工具,该工具可以模拟多个并发测试。

语法:
ab.exe –n 总的请求数 -c 并发数 url地址;
(1)创建一个表,表里面就只有一个字段,便于我们演示

(2)通过代码来完成,
从数据库中取出id的值(比如id=100)
把这个值+1(id=100+1)
再把该值存回到数据库(id=101)
(3)使用ab工具模拟并发操作。

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

(4)添加锁机制来进行测试。
把表里面的数据, 再改为100;

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

开始执行50个并发

测试效果如下;

2、使用mysql里面锁机制缺点
就是阻塞,假如有一张goods表,goods表里面有一个库存的字段,当前下订单时,如果锁定了goods表,还能执行查询goods表吗?
会阻塞拖慢整个网站的速度,一但锁定goods表(添加写锁,要更改库存),则其他进程就无法查询goods表。
3、可以使用文件锁


error_reporting(0);$conn = mysql_connect('localhost','root','root');mysql_query('use demo');mysql_query('set names utf8');//打开该文件$fh = fopen('./lock.txt','w');//添加锁flock($fh,LOCK_EX );//mysql_query('lock table a write');//添加写锁//取出id的值$res = mysql_query('select id from a');$row = mysql_fetch_assoc($res);$id = $row['id'];//执行该id+1运算$id = $id+1;//执行结果,再写入数据库mysql_query("update a set id = $id");//释放锁flock($fh,LOCK_UN );//mysql_query('unlock tables');

