【一】.无锁
场景:多个人购买一件商品,库存减少。
商品表:
主键 商品名 库存数量 id name stock 1 美女 200
代码:
$table = 'think_goods';
$where = ['id' => 1];
$good = Db::table($table)->where($where)->find();
if (!$good) {
throw new Exception('商品不存在');
}
if ($good['stock'] <= 0) {
throw new Exception('库存不足');
}
$isUpDate = Db::table($table)->where($where)->dec('stock')->update();
if (!$isUpDate) {
throw new Exception('扣除库存失败');
}
echo '扣除库存成功,下单成功';解释:这种代码虽然在查询库存的时候判断了库存数量大于0,但是并发下会出现库存为负值
【二】.乐观锁.
概念:乐观锁假设认为数据一般情况下不会造成冲突,只有数据在进行提交更新的时候才会检查会不会冲突,如果冲突返回错误信息给用户,不冲突则更新。乐观锁就是在应用层想办法解决。
场景:多个人购买一件商品,库存减少。
商品表:
主键 商品名 库存数量 id name stock 1 美女 10
代码1:
$table = 'think_goods';
$where = [
['id', '=', 1],
['stock', '>', 0],
];
$isUpdate = Db::table($table)->where($where)->dec('stock')->update();
if(!$isUpdate)
{
throw new Exception('抢购失败,库存不足');
}解释1:上面代码乐观的认为库存数量足够,因此只在最后更新库存的时候加上where条件,不满足条件无法更新,也是一种锁,更新失败提示用户库存不足即可。网上也有其他类似的方式,例如在表中添加一个version字段,每次更新的时候where条件加上version=查询的version,更新数据时再把version+1,其实道理一样。
【三】.悲观锁.
概念:在整个数据的处理过程中,将数据设置为锁定状态,因此悲观锁往往依赖于数据库提供的锁的机制。共享锁和排他锁都属于悲观锁
场景:多个人购买一件商品,库存减少。
商品表:
主键 商品名 库存数量 id name stock 1 美女 200
代码1: (排他锁,for update)
//01.开启事务
Db::startTrans();
try{
//02.加锁查询商品(for update 排他锁)
$table = 'think_goods';
$where = ['id' => 1];
$info = Db::table($table)->where($where)->lock(true)->find();
if (!$info) {
throw new Exception('商品不存在');
}
//03.检查库存是否足够
if (!$info['stock']) {
throw new Exception('库存不足');
}
//04.更新商品库存
$isUpdate = Db::table($table)->where($where)->dec('stock')->update();
if(!$isUpdate)
{
throw new Exception('更新数据异常');
}
//05.提交事务
Db::commit();
}catch (Exception $exception)
{
//06.事务回滚
Db::rollback();
//07.输出错误
var_dump($exception->getMessage());
}
exit('抢购成功');解释: 上面的代码使用了mysql的for update行锁,查询数据的时候就把本条数据锁定,其他进程只能读取不可修改本条记录,只到锁定的进程提交了事务或者回滚了事务,其他进程才能正常操作。上面的代码为了简洁外部少包装了异常try catch,遇到异常也回滚,否则容易造成死锁。但是如果是fpm这种情况就好多了,请求完成销毁一切,和mysql服务端断开连接,mysql发现客户端断开了则自动销毁锁。另外在测试mysql5.7中发现你长期通用锁不提交事务也不回滚,超过指定时间则自动销毁锁,抛出的异常(General error: 1205 Lock wait timeout exceeded; try restarting transaction)
提示:本文只是为了让大家区别乐观锁和悲观锁。而重点的悲观锁中的排他锁和共享锁将在其他文章叙述。一般来将大部分业务最好使用乐观锁处理,减少死锁或者表锁行锁的性能开销和安全风险。
在PHP中,大部分变量类型,如字符串,整型,浮点,数组等都是值类型的,而类和对象是引用类型.和其他语言有点差距.(1).在值类型中我们直接使用&符号表示指向对应变量的内存地址,当前变量和被指向的变量只要有1个的值被修改都会直接影响另外一个变量的值发生变化。(ps:还是非常节省内存的,可以使用...
PHP不像net支持多继承,自身只支持单继承,为了解决这个问题,php出了Trait这个特性,减少单继承语言的限制。并且能让代码复用率更高。说白了就是一个对象的属性和方法扩展工具一样。例如:trait exts { public f...
最近在编写windows php多线程的东西,从官网下载了PHP的线程安全版,尝试开启curl扩展extension=php_curl.dllphp -m 却提示 PHP Startup: Unable to load dynamic library 'C:\php\ext\php_curl...
<?php //如果支持exec函数,可以使用的方式 exec('chcp 65001'); //如果exec函数因安全问题禁用,可以使用的方式 pclose(popen('chcp 65001', 'r'));...
本教程使用的定时任务基于EasyTak,EasyTask官方文档:https://gitee.com/392223903/EasyTask(1).安装tp5.0或者5.1composer create-project topthink/think=5.0.* tp5&n...
安装php-redis扩展提示No releases available for package我直接去php官网下载redis扩展.tgz文件,然后直接用pecl安装本地文件pecl install ./redis.tgz...