当前位置:   article > 正文

redis的使用场景

redis的使用场景

目录

1. 热点数据缓存

1.1 什么是缓存?

1.2 缓存的原理

1.3 什么样的数据适合放入缓存中

1.4 哪个组件可以作为缓存

1.5 java使用redis如何实现缓存功能

1.5.1 需要的依赖

1.5.2  配置文件

 1.5.3 代码

 1.5.4 发现

1.6 使用缓存注解完成缓存功能

2. 分布式锁

2.1模拟高并发

2.2 使用syn和lock锁

2.3 模拟多服务器

 2.4 nginx代理集群

2.5 使用redis解决分布式锁文件


1. 热点数据缓存

1.1 什么是缓存?

 为了把一些经常访问的数据,放入缓存中以减少对数据库的访问频率。从而减少数据库的压力,提高程序的性能。(内存中存储)

1.2 缓存的原理

1.3 什么样的数据适合放入缓存中

  1. 查询频率高且修改频率低
  2.  数据安全性低

1.4 哪个组件可以作为缓存

  1. redis组件
  2. memory组件
  3. ehcache组件

1.5 java使用redis如何实现缓存功能

1.5.1 需要的依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-redis</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-web</artifactId>
  8. </dependency>
  9. <dependency>
  10. <groupId>com.baomidou</groupId>
  11. <artifactId>mybatis-plus-boot-starter</artifactId>
  12. <version>3.4.3</version>
  13. </dependency>
  14. <dependency>
  15. <groupId>mysql</groupId>
  16. <artifactId>mysql-connector-java</artifactId>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.projectlombok</groupId>
  20. <artifactId>lombok</artifactId>
  21. <optional>true</optional>
  22. </dependency>

1.5.2  配置文件

  1. server.port=8080
  2. #数据源
  3. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  4. spring.datasource.url=jdbc:mysql://localhost:3306/1suo?useUnicode=true&characterEncoding=utf-8&useSSL=false
  5. spring.datasource.username=root
  6. spring.datasource.password=12345678
  7. #mybatisplus的sql日志
  8. mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
  9. #mapper映射文件
  10. mybatis-plus.mapper-locations=classpath*:mapper/*.xml
  11. #redis配置
  12. spring.redis.host=172.16.7.192
  13. spring.redis.port=6379
  14. spring.redis.database=1

 1.5.3 代码

控制层

  1. package com.ls.controller;
  2. import com.ls.entity.Clazz;
  3. import com.ls.service.ClazzService;
  4. import com.ls.vo.R;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.web.bind.annotation.*;
  7. /**
  8. * @program: springboot-redis-cache
  9. * @description:
  10. * @author: 1suo
  11. * @create: 2024-07-24 19:56
  12. **/
  13. @RestController
  14. @RequestMapping("clazz")
  15. public class ClazzController {
  16. @Autowired
  17. private ClazzService clazzService;
  18. @DeleteMapping("delete")
  19. public R delete(Integer id) {
  20. return clazzService.delete(id);
  21. }
  22. @GetMapping("get")
  23. public R get(Integer id) {
  24. return clazzService.get(id);
  25. }
  26. @GetMapping("getAll")
  27. public R getAll() {
  28. return clazzService.getAll();
  29. }
  30. @PostMapping("save")
  31. public R save(@RequestBody Clazz clazz) {
  32. return clazzService.save(clazz);
  33. }
  34. @PutMapping("update")
  35. public R update(Clazz clazz) {
  36. return clazzService.update(clazz);
  37. }
  38. }

业务层

  1. package com.ls.service.impl;
  2. import com.ls.dao.ClazzDao;
  3. import com.ls.entity.Clazz;
  4. import com.ls.service.ClazzService;
  5. import com.ls.vo.R;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.data.redis.core.RedisTemplate;
  8. import org.springframework.data.redis.core.ValueOperations;
  9. import org.springframework.stereotype.Service;
  10. import sun.dc.pr.PRError;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. /**
  14. * @program: springboot-redis-cache
  15. * @description:
  16. * @author: 1suo
  17. * @create: 2024-07-24 19:57
  18. **/
  19. @Service
  20. public class ClazzServiceImpl implements ClazzService {
  21. @Autowired
  22. private ClazzDao clazzDao;
  23. @Autowired
  24. private RedisTemplate<String, Object> redisTemplate;
  25. @Override
  26. public R save(Clazz clazz) {
  27. int insert = clazzDao.insert(clazz);
  28. return new R(200,"保存成功",clazz);
  29. }
  30. @Override
  31. public R update(Clazz clazz) {
  32. int update = clazzDao.updateById(clazz);
  33. if (update>0){
  34. redisTemplate.opsForValue().set("clazz::" + clazz.getCid(),clazz);
  35. }
  36. return new R(200,"更新成功",clazz);
  37. }
  38. @Override
  39. public R delete(Integer id) {
  40. int delete = clazzDao.deleteById(id);
  41. if (delete>0){
  42. redisTemplate.delete("clazz::" + id);
  43. }
  44. return new R(200,"删除成功",id);
  45. }
  46. @Override
  47. public R get(Integer id) {
  48. ValueOperations<String, Object> forValue = redisTemplate.opsForValue();
  49. Object o = forValue.get("clazz::" + id);
  50. if(o!=null){
  51. return new R(200,"查询成功",(Clazz)o);
  52. }
  53. Clazz clazz = clazzDao.selectById(id);
  54. if (clazz!=null){
  55. forValue.set("clazz::" + id,clazz);
  56. }
  57. return new R(500,"查询成功",clazz);
  58. }
  59. @Override
  60. public R getAll() {
  61. List<Clazz> list = clazzDao.selectList(null);
  62. return new R(200,"查询成功",list);
  63. }
  64. }

dao层

  1. package com.ls.dao;
  2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  3. import com.ls.entity.Clazz;
  4. /**
  5. * @program: springboot-redis-cache
  6. * @description:
  7. * @author: 1suo
  8. * @create: 2024-07-25 08:41
  9. **/
  10. public interface ClazzDao extends BaseMapper<Clazz> {
  11. }

实体类

  1. package com.ls.entity;
  2. import com.baomidou.mybatisplus.annotation.IdType;
  3. import com.baomidou.mybatisplus.annotation.TableId;
  4. import com.baomidou.mybatisplus.annotation.TableName;
  5. import lombok.AllArgsConstructor;
  6. import lombok.Data;
  7. import lombok.NoArgsConstructor;
  8. /**
  9. * @program: springboot-redis-cache
  10. * @description:
  11. * @author: 1suo
  12. * @create: 2024-07-24 19:56
  13. **/
  14. @Data
  15. @NoArgsConstructor
  16. @AllArgsConstructor
  17. @TableName("tbl_clazz")
  18. public class Clazz {
  19. @TableId(type = IdType.AUTO)
  20. private Integer cid;
  21. private String cname;
  22. }

 配置类

  1. package com.ls.config;
  2. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  3. import com.fasterxml.jackson.annotation.PropertyAccessor;
  4. import com.fasterxml.jackson.databind.ObjectMapper;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.data.redis.connection.RedisConnectionFactory;
  8. import org.springframework.data.redis.core.RedisTemplate;
  9. import org.springframework.data.redis.core.StringRedisTemplate;
  10. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
  11. import org.springframework.data.redis.serializer.StringRedisSerializer;
  12. @Configuration
  13. public class RedisConfig {
  14. @Bean
  15. public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
  16. RedisTemplate<String, Object> template = new RedisTemplate<>();//创建redisTemplate对象
  17. StringRedisSerializer serializer = new StringRedisSerializer();//字符串序列化对象
  18. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//Jackson的序列化对象
  19. ObjectMapper om = new ObjectMapper();
  20. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  21. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  22. jackson2JsonRedisSerializer.setObjectMapper(om);
  23. template.setConnectionFactory(factory);
  24. // key序列化方式
  25. template.setKeySerializer(serializer);
  26. // value序列化
  27. template.setValueSerializer(jackson2JsonRedisSerializer);
  28. // value hashmap序列化
  29. template.setHashValueSerializer(jackson2JsonRedisSerializer);
  30. template.setKeySerializer(serializer);
  31. return template;
  32. }
  33. }

@MapperScan("com.ls.dao") 注解,将dao层自动代理为Mapper代理对象。

 1.5.4 发现

业务层代码除了要维护核心业务功能外,额外还要维护缓存的代码。

解决: 使用AOP面向切面编程。(spring框架用aop切面实现)

1.6 使用缓存注解完成缓存功能

必须spring缓存使用的组件。 

config:为解决序列化的问题

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

 开启缓存注解

 

 使用

  1. package com.ls.service.impl;
  2. import com.ls.dao.ClazzDao;
  3. import com.ls.entity.Clazz;
  4. import com.ls.service.ClazzService;
  5. import com.ls.vo.R;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.cache.annotation.CacheEvict;
  8. import org.springframework.cache.annotation.CachePut;
  9. import org.springframework.cache.annotation.Cacheable;
  10. import org.springframework.cache.annotation.EnableCaching;
  11. import org.springframework.data.redis.core.RedisTemplate;
  12. import org.springframework.data.redis.core.ValueOperations;
  13. import org.springframework.stereotype.Service;
  14. import sun.dc.pr.PRError;
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. /**
  18. * @program: springboot-redis-cache
  19. * @description:
  20. * @author: 1suo
  21. * @create: 2024-07-24 19:57
  22. **/
  23. @Service
  24. public class ClazzServiceImpl implements ClazzService {
  25. @Autowired
  26. private ClazzDao clazzDao;
  27. @Autowired
  28. private RedisTemplate<String, Object> redisTemplate;
  29. @Override
  30. public R save(Clazz clazz) {
  31. int insert = clazzDao.insert(clazz);
  32. return new R(200,"保存成功",clazz);
  33. }
  34. @CachePut(cacheNames = "clazz", key = "#clazz.cid")
  35. @Override
  36. public Clazz update(Clazz clazz) {
  37. int update = clazzDao.updateById(clazz);
  38. return clazz;
  39. }
  40. @CacheEvict(cacheNames = "clazz", key = "#id")
  41. @Override
  42. public R delete(Integer id) {
  43. int delete = clazzDao.deleteById(id);
  44. return new R(200,"删除成功",id);
  45. }
  46. @Cacheable(cacheNames = "clazz", key = "#id")
  47. @Override
  48. public Clazz get(Integer id) {
  49. Clazz clazz = clazzDao.selectById(id);
  50. return clazz;
  51. }
  52. @Override
  53. public R getAll() {
  54. List<Clazz> list = clazzDao.selectList(null);
  55. return new R(200,"查询成功",list);
  56. }
  57. }

2. 分布式锁

2.1模拟高并发

使用jmeter压测工具:

第一步:

 第二步:

 第三步:

 通过压测发现库存超卖和重卖了,解决办法使用锁

2.2 使用syn和lock锁

  1. public String decrement(Integer productid) {
  2. //根据id查询商品的库存
  3. int num = stockDao.findById(productid);
  4. synchronized (this) {
  5. if (num > 0) {
  6. //修改库存
  7. stockDao.update(productid);
  8. System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");
  9. return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";
  10. } else {
  11. System.out.println("商品编号为:" + productid + "的商品库存不足。");
  12. return "商品编号为:" + productid + "的商品库存不足。";
  13. }
  14. }
  15. }

 上面使用syn和lock虽然解决了并发问题,但是我们未来项目部署时可能要部署集群模式

2.3 模拟多服务器

点击增加一个服务器,同时启动后,实现模拟多服务器。 下面是服务器配置。

 启动俩个服务器:

 2.4 nginx代理集群

下载window版本的nginx实现代理集群。

nginx.conf配置文件:

 通过压测发现本地锁 无效了,使用redis解决分布式锁文件

2.5 使用redis解决分布式锁文件

 核心代码:

  1. @Service
  2. public class StockService {
  3. @Autowired
  4. private StockDao stockDao;
  5. @Autowired
  6. private RedissonClient redisson;
  7. //
  8. public String decrement(Integer productid) {
  9. RLock lock = redisson.getLock("product::" + productid);
  10. lock.lock();
  11. try {
  12. //根据id查询商品的库存: 提前预热到redis缓存中
  13. int num = stockDao.findById(productid);
  14. if (num > 0) {
  15. //修改库存---incr---定时器[redis 数据库同步]
  16. stockDao.update(productid);
  17. System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");
  18. return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";
  19. } else {
  20. System.out.println("商品编号为:" + productid + "的商品库存不足。");
  21. return "商品编号为:" + productid + "的商品库存不足。";
  22. }
  23. }finally {
  24. lock.unlock();
  25. }
  26. }
  27. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/893776
推荐阅读
相关标签
  

闽ICP备14008679号