redis的使用场景

发布于:2022-12-28 ⋅ 阅读:(271) ⋅ 点赞:(0)

目录

1.redis作为缓存

2.分布式锁


1.redis作为缓存

(1)数据存储在内存中,数据查询速度快。可以分摊数据库压力。

 (2)什么样的数据适合放入缓存。

查询频率比较高,修改频率比较低。

安全系数低的数据

(3)使用redis作为缓存

package com.wzl.qy151redisspringboot.service;

import com.wzl.qy151redisspringboot.dao.DeptMapper;
import com.wzl.qy151redisspringboot.entity.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;


@Service
public class DeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    //业务代码
    public Dept findById(Integer id){
        ValueOperations forValue = redisTemplate.opsForValue();
        //查询缓存
        Object o = forValue.get("dept::" + id);
        //缓存命中
        if(o!=null){
            return (Dept) o;
        }
        Dept dept = deptMapper.selectById(id);
        if(dept!=null){
            //存入缓存中
            forValue.set("dept::"+id,dept,2, TimeUnit.HOURS);
        }
        return dept;
    }

    public int deleteById(Integer id){
        redisTemplate.delete("dept::"+id);
        int row = deptMapper.deleteById(id);
        return row;
    }

    public Dept insert(Dept dept){
        int insert = deptMapper.insert(dept);
        return dept;
    }

    public Dept update(Dept dept){
        ValueOperations forValue = redisTemplate.opsForValue();
        forValue.set("dept::"+dept.getId(),dept,2, TimeUnit.HOURS);
        int insert = deptMapper.updateById(dept);
        return dept;
    }
}

        查看的缓存:前部分代码相同@before通知,后部分代码也相同后置通知。我们可以AOP完成缓存代码和业务代码分离.

        spring框架应该能想到。----使用注解完成。注解该解析

(1)把缓存的配置类加入

 @Bean
 public CacheManager cacheManager(RedisConnectionFactory factory) {
     RedisSerializer<String> redisSerializer = new StringRedisSerializer();
     Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
     //解决查询缓存转换异常的问题
     ObjectMapper om = new ObjectMapper();
     om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
     om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
     jackson2JsonRedisSerializer.setObjectMapper(om);
     // 配置序列化(解决乱码的问题),过期时间600秒
     RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
             .entryTtl(Duration.ofSeconds(600)) //缓存过期10分钟 ---- 业务需求。
             .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))//设置key的序列化方式
             .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) //设置value的序列化
             .disableCachingNullValues();
     RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
             .cacheDefaults(config)
             .build();
     return cacheManager;
 }

(2)使用开启注解缓存注解

(3)使用注解

//业务代码
 //使用查询注解:cacheNames表示缓存的名称 key:唯一标志---dept::key
 //先从缓存中查看key为(cacheNames::key)是否存在,如果存在则不会执行方法体,如果不存在则执行方法体并把方法的返回值存入缓存中
 @Cacheable(cacheNames = {"dept"},key="#id")
 public Dept findById(Integer id){
     Dept dept = deptMapper.selectById(id);
     return dept;
 }
//先删除缓存在执行方法体。
 @CacheEvict(cacheNames = {"dept"},key = "#id")
 public int deleteById(Integer id){
     int row = deptMapper.deleteById(id);
     return row;
 }

 //这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中,实现缓存与数据库的同步更新。
 @CachePut(cacheNames = "dept",key="#dept.id")
 public Dept update(Dept dept){
     int insert = deptMapper.updateById(dept);
     return dept;
 }

 

2.分布式锁

        使用测压工具测试高并发下带来线程安全问题

         我们看到同一个库存被使用了n次。数据库中库存为负数,线程安全问题导致

(1)解决方案:使用synchronized或者lock锁

package com.wzl.distrinctlock.service.impl;

import com.wzl.distrinctlock.dao.ProductStockDao;
import com.wzl.distrinctlock.service.ProductStockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ProductStockServiceImpl2 implements ProductStockService {
    @Autowired
    private ProductStockDao productStockDao;

    @Override
    public  String decreaseStock(Integer productId) {
              synchronized (this) {
                  //查看该商品的库存数量
                  Integer stock = productStockDao.findStockByProductId(productId);
                  if (stock > 0) {
                      //修改库存每次-1
                      productStockDao.updateStockByProductId(productId);
                      System.out.println("扣减成功!剩余库存数:" + (stock - 1));
                      return "success";
                  } else {
                      System.out.println("扣减失败!库存不足!");
                      return "fail";
                  }
              }

    }
}

使用synchronized 或者lock锁 如果我们搭建了项目集群,那么该锁无效。

 使用redis开集群项目

 

 发现又出现: 重复数字以及库存为负数。

 

 

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到