悲观锁

在悲观锁的情况下,为了保证事务的隔离性,就须要一致性锁定读。
读取数据时给加锁,其他事务无法改动这些数据。
改动删除数据时也要加锁,其他事务无法读取这些数据。

在做数据缓存的时候,通常都是把数据从数据库读取出来,然后放入缓存,接下来在缓存的有效期内都是从缓存读取数据减少数据库压力。但是在高并发环境下,就有可能出现问题,比如根据指定格式从redis下拿数据,但是当下key是不存在的,那么就需要往里面写数据,如果多个进程同时请求,会造成数据的二次写入,如果逻辑不复杂还不会出现大的问题,问题是假如这个key的数据会变化呢?那么这时候就需要加一个锁机制了,就是获取了锁权限的进程才有资格对数据操作。

(意思是,加入悲观锁,让拿到锁的进程,进行判断key操作,如果有就读取,如果没有就写入,读取的时候别的进程无法改动这些数据,如果要是写数据的时候别的事务不能读取这条数据)

提到悲观锁,先通过网上给出的一个比较形象的比喻

拿健身房比喻,门口挂着把钥匙(只有一把),想进去的人必须拿到这把钥匙才行,拿到钥匙的人可以进入,不管是热身、喝水还是跑步都可以,直到他出来把钥匙挂回墙上,下一个才能去争取,拿到的才可以再进去。

听着好像有点不人性化,所以悲观锁比较适合强一致性的场景,但效率比较低,特别是读的并发低。乐观锁则适用于读多写少,并发冲突少的场景。

实现要点和思路

1、一个任务在同一时间段内只能被一个用户所持有; 
2、避免出现死任务,即避免任务被用户长时间占有,无法释放。(使用redis的)

设置一个锁的key,setnx是原子操作,只能一个进程写入成功,写入成功返回true(表示获取锁权限),然后写入内容立即释放锁即删除锁key。

如果只用SETNX命令设置锁的话,如果当持有锁的进程崩溃或删除锁失败时,其他进程将无法获取到锁,问题就大了。

获取不到锁的进程去判断锁的剩余有效时间,如果为-1,那么表示没有设置过期时间,则设置锁的有效时间为5秒(预留5秒给拿到锁的进程处理时间,足够多了),返回true,等待锁删除。

<?php
$lock_key = 'LOCK_PREFIX' . $redis_key;
$is_lock = $redis->setnx($lock_key, 1); // 加锁-》将上面变量当做key,判断如果有key值,不做操作,如果没有,将lockkey的值设置为1
if($is_lock == true){ // 获取锁权限
$redis->setex($redis_key, $expire, $data); // 写入内容
// 释放锁
$redis->del($lock_key);
}else{
// 防止死锁
if($redis->ttl($lock_key) == -1){
$redis->expire($lock_key, 5);
}
return true; // 获取不到锁权限,直接返回
}

setnx :

只在键 key 不存在的情况下, 将键 key 的值设置为 value 。
若键 key 已经存在, 则 SETNX 命令不做任何动作。

setex:

将键 key 的值设置为 value , 并将键 key 的生存时间设置为 seconds 秒钟。

如果键 key 已经存在, 那么 SETEX 命令将覆盖已有的值。

php结合redis高并发下,悲观锁解决数据二次写入的更多相关文章

  1. [Redis] - 高并发下Redis缓存穿透解决

    高并发情况下,可能都要访问数据库,因为同时访问的方法,这时需要加入同步锁,当其中一个缓存获取后,其它的就要通过缓存获取数据. 方法一: 在方法上加上同步锁 synchronized //加同步锁,解决 ...

  2. 使用mysql悲观锁解决并发问题

    最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下: 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持 ...

  3. 基于Django的乐观锁与悲观锁解决订单并发问题的一点浅见

    订单并发这个问题我想大家都是有一定认识的,这里我说一下我的一些浅见,我会尽可能的让大家了解如何解决这类问题. 在解释如何解决订单并发问题之前,需要先了解一下什么是数据库的事务.(我用的是mysql数据 ...

  4. 悲观锁 vs 乐观锁 vs Redis

    企业面对高并发场景采用的方案. 比如 产品抢购高并发时的超发现象. 1 悲观锁悲观锁 需要数据库本身提供支持(Oracle和MySQL都是支持的).实现细节:当前 数据库事务 读取到产品后, 就将目标 ...

  5. 【Redis】Redis事务详解,Redis事务支持回滚(不支持悲观锁)

    1.redis事物参考:https://baijiahao.baidu.com/s?id=1613631210471699441&wfr=spider&for=pc (php操作red ...

  6. java高并发下的数据安全

    高并发下的数据安全 我们知道在多线程写入同一个文件的时候,会存现“线程安全”的问题(多个线程同时运行同一段代码,如果每次运行结果和单线程运行的结果是一样的,结果和预期相同,就是线程安全的).如果是My ...

  7. Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解

    Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解 说明:Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解,实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返 ...

  8. MySQL 乐观锁与悲观锁

    悲观锁 悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁. 悲观锁: ...

  9. Mysql悲观锁乐观锁区别与使用场景

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

随机推荐

  1. S5PV210 串口实验(中断方式)

    结合之前的串口实验(轮询方式)与中断体系分析,我们来做下中断方式的串口接收实验. start.S .global _start .global IRQ_handle _start: /* 关 Watc ...

  2. 深入浅出 JVM GC(2)

    # 前言 在 深入浅出 JVM GC(1) 中,限于上篇文章的篇幅,我们留下了一个问题 : 如何回收? 这篇文章将重点讲述这个问题. 在上篇文章中,我们也列出了一些大纲,今天我们就按照那个大纲来逐个讲 ...

  3. .12-浅析webpack源码之NodeWatchFileSystem模块总览

    剩下一个watch模块,这个模块比较深,先大概过一下整体涉及内容再分部讲解. 流程图如下: NodeWatchFileSystem const Watchpack = require("wa ...

  4. IdentityServer4 中文文档 -6- (简介)示例服务器和测试

    IdentityServer4 中文文档 -6- (简介)示例服务器和测试 原文:http://docs.identityserver.io/en/release/intro/test.html 目 ...

  5. java根据年月显示每周

    一.页面效果 1.展示7月份的所有周. 2.当前时间2018.08.02  ,  显示到本周. 二.前端代码 1.显示层的代码 <span id="weekyear"> ...

  6. Java基础——Servlet(八)文件上传下载

    一.简单的文件上传常见的组件Smartupload , Apache 的 commons FileUploadSmartupload上传的步骤: 1.初始化上传上下文 2.准备上传 3.保存文件 &l ...

  7. 【Spring】1、Spring 中的监听器 Listener

    一.接口 1.EventListener 2.HttpSessionAttributeListener   继承EventListener接口 HttpSessionAttributeListener ...

  8. 通过kubernetes构建ela服务

    一.kubernetes 通过yaml 创建pod与service apiVersion: extensions/v1beta1 kind: Deployment metadata: name: el ...

  9. HashMap底层实现原理(JDK1.8)源码分析

    ref:https://blog.csdn.net/tuke_tuke/article/details/51588156 http://www.cnblogs.com/xiaolovewei/p/79 ...

  10. Linux常用基本命令:三剑客命令之-awk 三元表达式

    awk 3元表达式,if...else结构都可以用3元表达式改写 ghostwu@dev:~/linux/awk$ awk -v FS=":" '{ type=$3>=100 ...