怎样理解mysql innodb的行级锁?
public function test_sql(){
set_time_limit(0);
$model = D('Liren/GroupPurchase');
$row = $model->lock(true)->where(array('id'=>1))->find();
if($row){
dump($row);
sleep(10);
}
}
test_sql 方法是带锁查询了一条数据,之后延时了十秒,在这同时,我开了另一个进程:
public function test_lock(){
$model = D('Liren/GroupPurchase');
$info = $model->find(1);
if($info){
dump($info);
}
}
在test_sql没有结束之前test_lock一直在等待。而且就算我在test_lock方法中查询的不是主键(id)为1的数据,也同样要等到test_sql结束之后才能执行。这样的话是不是整个表都锁住了,是不是需要继承thinkphp的AdvModel才能真正实现行级锁?
还有一个问题。事务和锁之间存在关系吗?
public function test_sql(){
set_time_limit(0);
$model = D('Liren/GroupPurchase');
$model->startTrans();
$row = $model->lock(true)->where(array('id'=>1))->find();
// echo $model->getLastSql();
if($row){
$ret = $model->lock(true)->save(array('id'=>1,'is_show'=>0));
echo $model->getLastSql();
}
if($ret){
$model->commit();
sleep(10);
echo 'success';
}
}
虽然事务是提交了,数据库的状态也一早就改变了,但还是必须等到test_sql进程结束之后 test_lock 方法才能输出数据,如果能在事务结束的时候表锁就能结束,这样是不是好一点。
小弟愚钝,望指点!
回复内容:
因为最近在做公司的一个秒杀项目,就是现在一些购物网站最常见的那种。但是考虑到并发的一些问题(也许并发不是主要的,主要的是现在有秒杀就会出现秒杀工具之类的)导致被秒出去的商品比实际库存还要多,所以就上网看了一下mysql的锁,公司用的是innodb引擎,thinkphp3.2框架,根据网上的相关资料,应该用的是行级锁(对于mysql,本人菜鸟,懂的不是很深入)。
public function test_sql(){
set_time_limit(0);
$model = D('Liren/GroupPurchase');
$row = $model->lock(true)->where(array('id'=>1))->find();
if($row){
dump($row);
sleep(10);
}
}
test_sql 方法是带锁查询了一条数据,之后延时了十秒,在这同时,我开了另一个进程:
public function test_lock(){
$model = D('Liren/GroupPurchase');
$info = $model->find(1);
if($info){
dump($info);
}
}
在test_sql没有结束之前test_lock一直在等待。而且就算我在test_lock方法中查询的不是主键(id)为1的数据,也同样要等到test_sql结束之后才能执行。这样的话是不是整个表都锁住了,是不是需要继承thinkphp的AdvModel才能真正实现行级锁?
还有一个问题。事务和锁之间存在关系吗?
public function test_sql(){
set_time_limit(0);
$model = D('Liren/GroupPurchase');
$model->startTrans();
$row = $model->lock(true)->where(array('id'=>1))->find();
// echo $model->getLastSql();
if($row){
$ret = $model->lock(true)->save(array('id'=>1,'is_show'=>0));
echo $model->getLastSql();
}
if($ret){
$model->commit();
sleep(10);
echo 'success';
}
}
虽然事务是提交了,数据库的状态也一早就改变了,但还是必须等到test_sql进程结束之后 test_lock 方法才能输出数据,如果能在事务结束的时候表锁就能结束,这样是不是好一点。
小弟愚钝,望指点!
既然是秒杀功能为什么还要用MySQL呢?为什么不考虑redis等内存缓存数据库呢?
毕竟内存的IO效率和磁盘的IO效率之间大概相差了中美之间经济实力那么多吧
那么谈谈锁的问题:
相比题主现在对概念应该还有些模糊,我先明确概念:
读锁->共享锁 (S)
写锁 -> 排它锁 (X)
兼容性:
X S
X 不兼容 不兼容
S 不兼容 兼容
还有一种叫乐观锁/悲观锁
这份回答很好,我直接拿来了,总结来说就是:
△乐观锁是通过逻辑实现,本质上并没有给数据库加锁
悲观锁是通过真实的数据库锁机制来完成的。
最后回到你的问题:
test_sql()函数: 首先要确认,在对表获取行锁的时候,要尽量的使用索引检索纪录,如果没有使用索引访问,那么即便你只是要更新其中的一行纪录,也是全表锁定的。要确保sql是使用索引来访问纪录的,必要的时候,请使用explain检查sql的执行计划,判断是否按照预期使用了索引。
由于mysql的行锁是针对索引加的锁,不是针对纪录加的锁,所以虽然是访问不同行的纪录,但是如果是相同的索引键,是会被加锁的。事务和锁没什么关系,锁的机制与存储引擎才有关
1.innodb 引擎支持行锁,但是不指定唯一索引键就会锁表
test_sql 中,使用了悲观锁,也就是 select where for update
当 where 条件指定了唯一索引键时---行锁
当非唯一索引键时---表锁
2.在事务中
select 操作共享锁
update,delete,insert 排它锁
commit 会把锁给取消
InnoDB引擎下,执行的SQL使用行级锁,还是全表锁。跟mysql采用的隔离级别、sql会使用到的索引、mysql自身针对这个sql的执行优化都有关系。
所以怎么理解mysql的锁,需要根据你在用的mysql的具体配置有关。有一篇博客讲的特别透彻,希望对你有用。http://blog.sae.sina.com.cn/archives/2127
下一篇: Netty:初识Netty