当前位置:首页 > PHP > 正文内容

mysql悲观锁,mysql乐观锁,mysql乐观锁怎么实现,mysql update 乐观锁

高老师7年前 (2020-04-30)PHP1844

【一】.无锁

场景:多个人购买一件商品,库存减少。

商品表:

主键   商品名   库存数量
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)

提示:本文只是为了让大家区别乐观锁和悲观锁。而重点的悲观锁中的排他锁和共享锁将在其他文章叙述。一般来将大部分业务最好使用乐观锁处理,减少死锁或者表锁行锁的性能开销和安全风险。

扫描二维码推送至手机访问。

版权声明:本文由高久峰个人博客发布,如需转载请注明出处。

本文链接:https://blog.20230611.cn/post/133.html

分享给朋友:

“mysql悲观锁,mysql乐观锁,mysql乐观锁怎么实现,mysql update 乐观锁” 的相关文章

 php文件锁解决高并发

php文件锁解决高并发

前面的文章对于高并发下单商品导致商品库存为负值的问题请先阅读再阅读本篇文章一定对您有帮助,建议亲手测试较好。加上文件锁后的下单处理代码:【一】.阻塞模式:(如果其他进程已经加锁文件,当前进程会一直等其他进程解锁文件后继续执行)<?php //连接数据库 $con=mysqli_connect(...

php scoket,php webscoket,php webscoket 服务器

php scoket,php webscoket,php webscoket 服务器

项目需要使用websocket推送最新订单,客户服务器非linux不支持swoole,因此使用原生,直接上代码(1).PHP服务端<?php ini_set('error_reporting', E_ALL ^ E_NOTICE); ini_set...

PHP getenv函数和putenv函数的学习

PHP getenv函数和putenv函数的学习

(1).在PHP中可以查看的环境变量包括: (1.1).电脑环境变量 (2.1).服务器环境变量(2).getenv()函数获取一个环境变量的值.参数1是环境变量的key,参数2值为true的时候仅从你的电脑环境变量中查找,参数2值为false会从两种变量中全部查询//获取我电脑登录的用户名,输出A...

php finally使用

php finally使用

<?php /**  * @throws Exception  */ function curl() {     throw  new \Exception('err...

php代理下载,php代下载文件,php下载远程文件,php远程文件下载

php代理下载,php代下载文件,php下载远程文件,php远程文件下载

经常我们下载国外资源容易被墙,可以通过php脚本获取远程文件流然后输出给我们的浏览器来下载。<?php //设置下载文件的url $url = 'https://mirrors.huaweicloud.com/ubuntukylin/ubuntukylin-19....

php mcrypt扩展被废弃的解决方案

php mcrypt扩展被废弃的解决方案

使用openssl扩展对应替换mcrypt的函数,(比较麻烦,但是openssl是未来趋势)在新版php中编译mcrypt扩展使用一个纯php代码实现的mcrypt扩展库,git地址为https://github.com/phpseclib/mcrypt_compat,每个mcrypt的方法都已经实...