测试redis分布式锁

1、基础知识:

通过HttpServletRequest获取对方请求的IP地址
request.getRemoteAddr()直接请求到服务器,获取对方的IP地址
request.getHeader("")通过nginx负载均衡访问的服务器,获取对方的IP地址。
在这里插入图片描述

@RequestMapping("{skuId}.html")
public String item(@PathVariable String skuId, ModelMap modelMap, HttpServletRequest request){

    String IP = request.getRemoteAddr();   //直接请求到服务器,获取对方的IP地址

    //request.getHeader("");  通过nginx负载均衡访问的服务器,获取对方的IP地址

2、设置分布式锁防止redis缓存击穿
(1)第1位同学先请求页面,就有第1条线程先进来。先查询缓存但是没查到,就去申请设置锁,并且拿到了锁,有权在10秒的过期时间内访问数据库。
为了看到设置锁的效果,这里设置第1位同学的线程等待5秒再去查询数据库和把结果存入redis,再归还删除锁
(2)第2名同学紧接着也请求页面,查询缓存但没查到。就申请设置锁。因为第1名同学还在等待5秒钟,还没有归还删除锁。
所以第2名同学就拿不到锁,也线程等待3秒,本方法自旋1次(第2名同学照样拿不到锁),线程继续等待3秒,本方法自旋第2次(正常从缓存查到数据)
(3)5秒过去了,第1名同学的线程开始执行,查询数据库和把结果存入redis,再归还删除锁。
(4)这样第2名同学的线程第2次自旋本方法,查询缓存,查到了,成功访问到前端页面!!!
在这里插入图片描述
3、实现代码如下(好好理解里面的注释):
基础知识:

Thread.sleep(1000*5) //线程睡5秒
Thread.currentThread().getName() //获取线程的名称
@Override
//用户购买商品页面:查看sku商品,sku图片集合
public PmsSkuInfo getSkuById(String skuId , String IP) {

    System.out.println("ip为:"+IP+"的同学的线程:"+Thread.currentThread().getName()+"正准备进入商品详情页面");
    PmsSkuInfo pmsSkuInfo = new PmsSkuInfo();

    //连接缓存
    Jedis jedis = redisUtil.getJedis();

    //查询缓存
    String skuKey = "sku:"+skuId+":info";
    String skuJson = jedis.get(skuKey);   //根据skuId到redis缓存查询得到一个json的字符串

    if(StringUtils.isNotBlank(skuJson)) {   //如果不等于空,即是可以在缓存查到
        pmsSkuInfo = JSON.parseObject(skuJson,PmsSkuInfo.class);  //把查询到的json字符串 转为 java对象
        System.out.println("ip为:"+IP+"的同学的线程:"+Thread.currentThread().getName()+"成功从缓存获取商品详情页面QWQ");

    }else {
        //如果缓存没有,就查询mysql数据库

        System.out.println("ip为:"+IP+"的同学的线程:"+Thread.currentThread().getName()+"发现缓存没有,申请获取锁");
        //设置分布式锁,防止缓存击穿。让用户有秩序的拿锁访问数据库,而不是一窝蜂进到数据库
        String ok = jedis.set("sku:" + skuId + ":lock", "1", "nx", "px", 10*1000);
        if(StringUtils.isNotBlank(ok)&&ok.equals("OK")){  //设置锁返回ok成功,允许这位用户访问数据库,10秒后过期时间,再允许下一位访问
                                    //注意返回来的字符串OK是大写!
            System.out.println("ip为:"+IP+"的同学的线程:"+Thread.currentThread().getName()+"拿到了锁"+"sku:" + skuId + ":lock"+",有权在10秒过期时间内访问数据库");


            System.out.println("ip为:"+IP+"的同学的线程:"+Thread.currentThread().getName()+"让该线程等待5秒。。。");


            try {
                Thread.sleep(1000*5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            pmsSkuInfo = getSkuByIdFromDb(skuId);  //建立redis缓存服务器,就是为了保护这行代码:查询数据库的操作
            if(pmsSkuInfo!=null) {
                //mysql查询结果存入redis
                jedis.set("sku:"+skuId+":info", JSON.toJSONString(pmsSkuInfo));    //把java对象 转为 json字符串

            }else {  //mysql查询结果为null,防止缓存穿透!!!!

                //把这个不存在的skuId设为:空值json字符串null,并存到redis服务器中。
                jedis.setex("sku:"+skuId+":info",60*3, JSON.toJSONString(""));
                //seconds是秒。3分钟内再有请求这skuId,就直接返回一个空的对象给前端(没有任何信息)。不再执行查询数据库操作
            }

            jedis.del("sku:" + skuId + ":lock");   //访问数据库结束后,删除锁。下一个用户继续拿锁访问!
            System.out.println("ip为:"+IP+"的同学的线程:"+Thread.currentThread().getName()+"访问数据库完毕,归还并删除锁:"+"sku:" + skuId + ":lock");

        }else {  //设置锁不成功,自旋(设置该线程睡眠几秒,再重新尝试访问本方法)

            System.out.println("ip为:"+IP+"的同学的线程:"+Thread.currentThread().getName()+"没拿到锁,开始自旋!");

            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


            return getSkuById(skuId, IP);   //这里要return返回这个方法重新访问,同一条线程!!
                                        //不加return,则创建一条新的线程,原来的线程还是访问不到,即原来的线程成了一条孤儿线程!
        }

    }
    jedis.close();   //关闭缓存连接
    return pmsSkuInfo;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了测试 Redis 分布式锁,你可以按照以下步骤进行操作: 1. 确保你已经安装了 Redis,并且可以通过命令行或者其他方式连接到 Redis 服务器。 2. 创建一个测试程序或者脚本,用于模拟多个并发请求获取和释放 Redis 分布式锁的情况。 3. 在测试程序中,使用 Redis 客户端库连接到 Redis 服务器。 4. 在测试程序中,创建多个并发线程或者进程,每个线程或进程都会尝试获取 Redis 。 5. 在每个线程或进程中,使用 Redis 的 SETNX 命令尝试获取。如果 SETNX 返回 1,表示获得了;如果返回 0,表示已经被其他线程或进程持有。 6. 如果获取到,执行需要加的业务逻辑;如果未获取到,等待一段时间后再次尝试获取。 7. 在业务逻辑执行完毕后,使用 Redis 的 DEL 命令释放。 8. 在测试程序中,记录每个线程或进程获取和释放的情况,以及的持有时间和并发冲突情况。 9. 执行测试程序,观察输出结果,检查是否存在并发冲突和的正确获取和释放。 10. 根据测试结果进行分析和调优,修改测试程序或者业务逻辑,以确保 Redis 分布式锁的正确性和高可用性。 请注意,在测试分布式锁时,你可能需要考虑以下情况: - 并发请求的数量和频率 - 的超时时间和自动释放机制 - 的重入性和可重入性 - 异常情况下的的释放和恢复机制 - 的可靠性和高可用性 以上是一般的测试步骤,你可以根据具体的使用场景和需求进行适当调整和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值