【一】.无锁
场景:多个人购买一件商品,库存减少。
商品表:
主键 商品名 库存数量 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)
提示:本文只是为了让大家区别乐观锁和悲观锁。而重点的悲观锁中的排他锁和共享锁将在其他文章叙述。一般来将大部分业务最好使用乐观锁处理,减少死锁或者表锁行锁的性能开销和安全风险。
xmlrpc协议是通过http请求xml数据进行通信。webservice中和它相同的是soap。soap调用的确很简单,但是创建wsdl太繁琐,效率低下。xmlrpc很好的解决这个问题。(1).创建xmlrpc服务端(求和函数api)function getSum($method,$ar...
ThinkPHP中有一个debug调试功能,能输出报错文件的信息,并能看到这个函数被哪些函数调用,从框架的启动开始记录,特别方便调试。于是研究了下它的底层给予了实现。<?php //--框架核心--Start //框架内置错误处理 function errDealWith($er...
(1).在PHP中可以查看的环境变量包括: (1.1).电脑环境变量 (2.1).服务器环境变量(2).getenv()函数获取一个环境变量的值.参数1是环境变量的key,参数2值为true的时候仅从你的电脑环境变量中查找,参数2值为false会从两种变量中全部查询//获取我电脑登录的用户名,输出A...
<?php $member = new class { public function getInfo() { ...
使用openssl扩展对应替换mcrypt的函数,(比较麻烦,但是openssl是未来趋势)在新版php中编译mcrypt扩展使用一个纯php代码实现的mcrypt扩展库,git地址为https://github.com/phpseclib/mcrypt_compat,每个mcrypt的方法都已经实...
php event扩展在windows中依赖于php_sockets扩展,因此在php.ini中必须先加载php sockets扩展,如下。extension=sockets extension=event...