【一】.无锁
场景:多个人购买一件商品,库存减少。
商品表:
主键 商品名 库存数量
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)
提示:本文只是为了让大家区别乐观锁和悲观锁。而重点的悲观锁中的排他锁和共享锁将在其他文章叙述。一般来将大部分业务最好使用乐观锁处理,减少死锁或者表锁行锁的性能开销和安全风险。
1.解压后,上传整个文件夹至服务器根目录2.在网站的一个公用文件(如数据库的连接文件)中加入代码:if(is_file($_SERVER['DOCUMENT_ROOT'].'/360safe/360webscan.php')){ &n...
<?PHP $a=0.5*100; if(is_int($a)){ echo'int'; } else{ echo'not int'; } ...
通过经纬度转换为城市名称,并获得城市的编号,通常在全国类型的商城中比较通用。//经纬度转城市名称(返回城市id,城市名称) //$ak开发密钥,$lat纬度,$lng经度,$type返回数据类型 public function getCityName($ak,$lat,$lng)...
开启错误提示代码:ini_set("display_errors", "On"); error_reporting(E_ALL | E_STRICT);关闭错误提示代码:error_reporting(E_ALL ^&n...
md5/sha1+salt方式是目前各大cms常用的加密方式,虽然salt安全,但是各大md5网站也在研究这个方向,那么我们应该选择password_hash动态hash来助力,一种密码有多种hash结果.看代码模拟登陆.<?php //01.注册 $user ='zhang...
php多进程应用场景主要是非web端,fpm下是不支持多进程的,非类linux操作系统都不支持,请在cli模式使用.可以使用多进程做任务分发,批量计算,批量文件处理,批量爬虫,网络运维等等。下面看一份简单的入门demo//创建子进程 $pid=pcntl_fork(); //返回-1,创建失败,不...