redis分布式锁

1. 正文

1. 使用redis作为分布式锁。
2. redis中常见的面试题。
    (1)redis缓存穿透,以及缓存雪崩。

2. 使用redis作为分布式锁。

锁场景:

package com.ykq.distributedlock.service;

import com.ykq.distributedlock.dao.StockDao;
import com.ykq.distributedlock.entity.Stock;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @Author 闫克起
 * @Date 2021/4/16 14:30
 * @Version 1.0
 */
@Service
public class StockService02 {

    @Resource
    private StockDao stockDao;

    public String decrStock(Integer productId) {//synchronized () 同步方法    同步代码块
         //查询对应的id的库存
        synchronized (this) {
            Stock stock = stockDao.selectById(productId);
            if (stock.getNum() > 0) {
                //根据id修改库存
                stock.setNum(stock.getNum() - 1);
                stockDao.updateById(stock);
                System.out.println("库存剩余:" + (stock.getNum()));
                return "库存减少成功";
            } else {
                return "库存不足";
            }
        }
    }
}

这中锁不适合分布式项目。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jguMBb15-1618972450416)(assets\1618559864593.png)]

使用redis解决分布式锁的问题

package com.ykq.distributedlock.service;

import com.ykq.distributedlock.dao.StockDao;
import com.ykq.distributedlock.entity.Stock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @Author 闫克起
 * @Date 2021/4/16 14:30
 * @Version 1.0
 */
@Service
public class StockService {

    @Resource
    private StockDao stockDao;

    @Autowired
    private StringRedisTemplate redisTemplate;

    public String decrStock(Integer productId) {//synchronized () 同步方法    同步代码块
        Boolean flag = redisTemplate.opsForValue().setIfAbsent("product::" + productId, "ykq",30, TimeUnit.SECONDS);
        //查询对应的id的库存
         if(flag) {//获取锁了
             try {
                 Stock stock = stockDao.selectById(productId);
                 if (stock.getNum() > 0) {
                     //根据id修改库存
                     stock.setNum(stock.getNum() - 1);
                     stockDao.updateById(stock); //异常发生
//                   int c=10/0;
                     System.out.println("库存剩余:" + (stock.getNum()));
                     return "库存减少成功";
                 } else {
                     return "库存不足";
                 }
             }catch (Exception e){
                  throw  new RuntimeException(e.getMessage());
             }
             finally {
                 redisTemplate.delete("product::" + productId);//释放锁资源 一定再finally
             }
         }else{
             System.out.println("服务器正忙请稍后再试..........");
             return "服务器正忙请稍后再试..........";
         }
    }
}

使用第三方组件redisson-----专门用于解决分布式问题。

       <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.13.4</version>
        </dependency>
   @Bean
    public RedissonClient getRedisson(){
        Config config=new Config();
        config.useSingleServer().setAddress("redis://192.168.213.188:6379");
        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }
package com.ykq.distributedlock.service;

import com.ykq.distributedlock.dao.StockDao;
import com.ykq.distributedlock.entity.Stock;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @Author 闫克起
 * @Date 2021/4/16 14:30
 * @Version 1.0
 */
@Service
public class StockService {

    @Resource
    private StockDao stockDao;

    @Autowired
    private RedissonClient redisson; 

    public String decrStock(Integer productId) {//synchronized () 同步方法    同步代码块
        RLock lock = redisson.getLock("product::" + productId);//获取锁对象
        try {
            lock.tryLock(60,20,TimeUnit.SECONDS); //自己别设置时间。
            Stock stock = stockDao.selectById(productId);
            if (stock.getNum() > 0) {
                //根据id修改库存
                stock.setNum(stock.getNum() - 1);
                stockDao.updateById(stock); //异常发生
//                   int c=10/0;
//                Thread.sleep(35000);
                System.out.println("库存剩余:" + (stock.getNum()));
                return "库存减少成功";
            } else {
                return "库存不足";
            }
        }catch (Exception e){
             throw  new RuntimeException(e.getMessage());
        }
        finally {
            lock.unlock();
        }
    }
}

3. redis的面试题

1. redis缓存穿透? 如何避免缓存穿透。
   (1)数据库中没有该记录,而缓存中没有该记录。而这时有人恶意访问这种数据。 直接访问数据库。

解决方案:
   (1) 如果数据库中不存在该对象,则往缓存中放入一个空对象,并且设置很短的过期时间。
   
2.缓存的雪崩?如何避免?
  (1)再某一时刻,缓存中没有该记录,而这时会有大量的请求。这些请求打压到数据库。
       比如: 项目刚刚上线。------预访问热点数据。
             某一个缓存的时间到了。----> 失效时间是一个散列值。
             使用队列: ----->每次有限的请求访问数据库。
             
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值