thinkphp中的lock与mysql的for update的使用注意事项
Posted 千年寒冰火
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了thinkphp中的lock与mysql的for update的使用注意事项相关的知识,希望对你有一定的参考价值。
一、数据库需要锁表的场景
- 场景1,对于资金和商品数量,非常重要。在同一时间内必须只有一个连接能够修改。
- 场景2:一个表A的值,依赖于表B的值,那么我在计算A更新值时,必须保证这个时间内,B表的值没有发生变化
二、 在thinkphp框架锁表的实现
-
使用模型类,调用lock()方法, 参数true是全局范围的,false只是当前链接
-
lock()调用会在sql语句后面,加上“for update”.
-
lock生效的条件,必须方式一个事务中,可以使用所有表开启Db::stratTrans(),Db::commit()之后锁表结束
-
//单个表事务 $user = new User(); $db = $user->db(true); $db->startTrans(); $res = $user->lock(true)->where(["id" => 1])->field(\'mobile,username\')->find(); sleep(3); // 休眠3秒,ID=1的行会锁表3秒 $db->commit();
-
//多个表事务 Db::stratTrans(); User::lock(true)->where(["id" => 1])->field(\'mobile,username\')->find(); sleep(3); // 休眠3秒,ID=1的行会锁表3秒 Db::commit();//或者回退也是户释放的,Db:rollback();
-
-
lock生效过程中,其他的并发请求中的Update操作都会出于阻塞,等待的状态
-
lock使用的注意事项,lock的条件,一定要用主键或唯一索引键,否则容易导致,整个表被锁住,而导致其他服务都出于等待中。原因,下面会讲。
三、mysql中for update
-
for update是在数据库中上锁用的,可以为数据库中的行上一个排它锁。当一个事务的操作未完成时候,其他事务可以读取但是不能写入或更新。
-
InnoDB默认是行级别的锁,当有明确指定的主键时候,是行级锁。否则是表级别。
-
for update 仅适用于InnoDB,并且必须开启事务,在begin与commit之间才生效。
-
锁的具体实例,假设表foods ,存在有id跟name、status三个字段,id是主键,status有索引。
-
明确指定主键,并且有此记录,行级锁
SELECT * FROM foods WHERE id=1 FOR UPDATE; SELECT * FROM foods WHERE id=1 and name=’咖啡色的羊驼’ FOR UPDATE;
-
明确指定主键/索引,若查无此记录,无锁
SELECT * FROM foods WHERE id=-1 FOR UPDATE;
-
无主键/索引,表级锁。影响非常大
SELECT * FROM foods WHERE name=’咖啡色的羊驼’ FOR UPDATE;
-
主键/索引不明确,表级锁。影响非常大
SELECT * FROM foods WHERE id<>’3’ FOR UPDATE; SELECT * FROM foods WHERE id LIKE ‘3’ FOR UPDATE;
-
-
for update nowait 锁住表或者锁住行,只允许当前事务进行操作(读写),其他事务被拒绝,事务占据的statement连接也会被断开
以上是关于thinkphp中的lock与mysql的for update的使用注意事项的主要内容,如果未能解决你的问题,请参考以下文章
MySQL for update 到底是 row lock / table lock
mysql 报root用户名locked Access denied for user ‘root‘@‘localhost‘. Account is locked
MySQL5.6 Waiting for Commit Lock
innodb_locks_unsafe_for_binlog参数解析