🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
百度百科上的解释:大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。 **悲观锁比较适合强一致性的场景,但效率比较低,特别是读的并发低。乐观锁则适用于读多写少,并发冲突少的场景。** ```php <?php /** * redis实战 * * 实现悲观锁机制 * * @author TIGERB <https://github.com/TIGERB> * @example php pessmistic-lock.php */ $timeout = 5000; $redis = new \Redis(); $redis->connect('127.0.0.1', 6379); do { $microtime = microtime(true) * 1000; $microtimeout = $microtime+$timeout+1; // 上锁 $isLock = $redis->setnx('lock.count', $microtimeout); if (!$isLock) { $getTime = $redis->get('lock.count'); if ($getTime > $microtime) { // 睡眠 降低抢锁频率 缓解redis压力 usleep(5000); // 未超时继续等待 continue; } // 超时,抢锁,可能有几毫秒级时间差可忽略 $previousTime = $redis->getset('lock.count', $microtimeout); if ((int)$previousTime < $microtime) { break; } } } while (!$isLock); $count = $redis->get('count')? : 0; // file_put_contents('/var/log/count.log.1', ($count+1)); // 业务逻辑 echo "执行count加1操作~ \n\n"; $redis->set('count', $count+1); // 删除锁 $redis->del('lock.count'); // 打印count值 $count = $redis->get('count'); echo "count值为:$count \n"; ``` **另外的方法** ``` function lock($strMutex, $intTimeout) { $objRedis = new Redis(); //使用setnx原子型操作加锁 $intRet = $objRedis->setnx($strMutex, 1); if ($intRet) { //设置过期时间,防止死任务的出现 $objRedis->expire($strMutex, $intTimeout); return true; } return false; } ``` ``` function lock($strMutex, $intTimeout, $intMaxTimes = 0) { $objRedis = new Redis(); //使用incr原子型操作加锁 $intRet = $objRedis->incr($strMutex); if ($intRet === 1) { //设置过期时间,防止死任务的出现 $objRedis->expire($strMutex, $intTimeout); return true; } if ($intMaxTimes > 0 && $intRet >= $intMaxTimes && $objRedis->ttl($strMutex) === -1) { //当设置了最大加锁次数时,如果尝试加锁次数大于最大加锁次数并且无过期时间则强制解锁 $objRedis->del($strMutex); } return false; } ``` ``` function lock($strMutex, $intTimeout) { $objRedis = new Redis(); //使用setnx操作加锁,同时设置过期时间 $strRet = $objRedis->set($strMutex, 1, 'ex', $intTimeout, 'nx'); if ($strRet === 'OK') { return true; } return false; } ```