Redis数据结构存储系统:第二章:如何使用

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Redis数据结构存储系统:第二章:如何使用

Redis与SpringBoot整合:

第一步:在项目中引入

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

第二步:将连接池和配置类创建好


RedisUtil:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisUtil {
    private JedisPool jedisPool;
    public void initPool(String host,int port ,int database){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(200);
        poolConfig.setMaxIdle(30);
        poolConfig.setBlockWhenExhausted(true);
        poolConfig.setMaxWaitMillis(10*1000);
        poolConfig.setTestOnBorrow(true);
        jedisPool=new JedisPool(poolConfig,host,port,20*1000);
    }
    public Jedis getJedis(){
        Jedis jedis = jedisPool.getResource();
        return jedis;
    }
}

RedisConfig:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration//Spring容器中的注解
public class RedisConfig {
    //读取配置文件中的redis的ip地址,@Value注入赋值
    @Value("${spring.redis.host:disabled}")
    private String host;
    @Value("${spring.redis.port:0}")
    private int port;
    @Value("${spring.redis.database:0}")
    private int database;
    @Bean//将返回值给Spring,Spring容器中就有了RedisUtil(连接池)
    public RedisUtil getRedisUtil(){
        if(host.equals("disabled")){
            return null;
        }
        RedisUtil redisUtil=new RedisUtil();
        redisUtil.initPool(host,port,database);
        return redisUtil;
    }
}

在哪个项目中使用Redis就在application.properties中配置以下:


 

客户端登录:

cd /usr/local/redis/bin

./redis-cli -h 192.168.0.100 -p 6379

192.168.0.100:6379> ping

PONG

测试一下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class GmallManageServiceApplicationTests {
  @Autowired
  RedisUtil redisUtil;
  @Test
  public void contextLoads() {
    Jedis jedis = redisUtil.getJedis();
    String ping = jedis.ping();
    System.out.println(ping);
  }
}

使用redis进行业务开发

开始开发先说明redis key的命名规范,由于Redis不像数据库表那样有结构,其所有的数据全靠key进行索引,所以redis数据的可读性,全依靠key。

企业中最常用的方式就是:object:id:field

    比如:sku:1314:info

                          user:1092:password

拿一个之前的例子:

     比如:sku:1314:info
                           user:1092:password
拿一个之前的例子:
public

以上基本实现使用缓存的方案。

高并发时可能会出现的问题:

但在高并发环境下还有如下三个问题。

  1. 如果redis宕机了,或者链接不上,怎么办?
  2. 如果redis缓存在高峰期到期失效,在这个时刻请求会向雪崩一样,直接访问数据库如何处理?
  1. 如果用户不停地查询一条不存在的数据,缓存没有,数据库也没有,那么会出现什么情况,如何处理?
 public SkuInfo getSkuInfo(String skuId){
    SkuInfo skuInfo = null;
    try {
        Jedis jedis = redisUtil.getJedis();
        String skuInfoKey = ManageConst.SKUKEY_PREFIX + skuId + ManageConst.SKUKEY_SUFFIX;
        String skuInfoJson = jedis.get(skuInfoKey);
        if (skuInfoJson == null || skuInfoJson.length() == 0) {
            System.err.println(Thread.currentThread().getName()+"缓存未命中!");
            String skuLockKey = ManageConst.SKUKEY_PREFIX + skuId + ManageConst.SKULOCK_SUFFIX;
            String lock = jedis.set(skuLockKey, "OK", "NX", "PX", ManageConst.SKULOCK_EXPIRE_PX);
            if ("OK".equals(lock) ){
                System.err.println(Thread.currentThread().getName()+"获得分布式锁!");
                skuInfo = getSkuInfoFromDB(skuId);
                if(skuInfo==null){
                    jedis.setex(skuInfoKey, ManageConst.SKUKEY_TIMEOUT, "empty");
                    return null;
                }
                String skuInfoJsonNew = JSON.toJSONString(skuInfo);
                jedis.setex(skuInfoKey, ManageConst.SKUKEY_TIMEOUT, skuInfoJsonNew);
                jedis.close();
                return skuInfo;
            }else{
                System.err.println(Thread.currentThread().getName()+"未获得分布式锁,开始自旋!");
                Thread.sleep(1000);
                jedis.close();
                return   getSkuInfo(  skuId);
            }
        } else if(skuInfoJson.equals("empty")){
            return null;
        } else {
            System.err.println(Thread.currentThread().getName()+"缓存已命中!!!!!!!!!!!!!!!!!!!");
            skuInfo = JSON.parseObject(skuInfoJson, SkuInfo.class);
            jedis.close();
            return skuInfo;
        }
    }catch (JedisConnectionException e){
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return getSkuInfoFromDB(skuId);
}

最近写的也一样:

controller:

    @RequestMapping("{skuId}.html")
    public String item(@PathVariable("skuId") String skuId, ModelMap map, HttpServletRequest request){
        SkuInfo skuInfo = skuService.item(skuId,request.getRemoteAddr());
    }

service接口我就不写了

Serviceimpl:

@Override
    public SkuInfo item(String skuId,String ip) {
        System.out.println(ip+"访问"+skuId+"商品");
        SkuInfo skuInfo = null;
        //从redis获取redis的客户端jedis
        Jedis jedis = redisUtil.getJedis();
        // 从缓存中取出skuId的数据
        String skuInfoStr = jedis.get("sku:"+skuId+":info");
        //Json格式转成实体类类型
        skuInfo = JSON.parseObject(skuInfoStr, SkuInfo.class);
        //从db中取出sku的数据
        //缓存中没有
        if(skuInfo == null){
            System.out.println(ip+"发现缓存中没有"+skuId+"商品数据,申请分布式锁");
            // 拿到分布式锁
            String OK = jedis.set("sku:" + skuId + ":lock", "1", "nx", "px", 10000);
            if(StringUtils.isBlank(OK)){
                System.out.println(ip+"分布式锁申请失败,三秒后开始自旋");
                // 缓存锁被占用,等一会儿继续申请
                try {
                    Thread.sleep(3000);//让它等3秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return item(skuId,ip);//自旋,这里没有启动新线程,item(skuId,ip);才会启动新线程
            }else{
                System.out.println(ip+"分布式锁申请成功,访问数据库");
                // 拿到缓存锁,可以访问数据库
                skuInfo = getSkuInfo(skuId);
            }
            System.out.println(ip+"成功访问数据库后,归还锁,将"+skuId+"商品放入缓存");
            jedis.del("sku:"+skuId+":lock");
        }
        //关闭redis客户端
        jedis.close();
        return skuInfo;
    }

getSkuInfo方法:

    public SkuInfo getSkuInfo(String skuId) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(skuId);
        SkuInfo skuInfos = skuInfoMapper.selectOne(skuInfo);
        SkuImage skuImage = new SkuImage();
        skuImage.setSkuId(skuId);
        List<SkuImage> skuImages = skuImageMapper.select(skuImage);
        skuInfos.setSkuImageList(skuImages);
        return skuInfos;
    }

如果对于


String skuInfoStr = jedis.get("sku:"+skuId+":info");


String OK = jedis.set("sku:" + skuId + ":lock", "1", "nx", "px", 10000);


jedis.del("sku:"+skuId+":lock");



不太理解,大家可以看看前一章节的博客,或者去官网查看



我这里截下来一部分



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
存储 缓存 监控
局域网屏幕监控系统中的Python数据结构与算法实现
局域网屏幕监控系统用于实时捕获和监控局域网内多台设备的屏幕内容。本文介绍了一种基于Python双端队列(Deque)实现的滑动窗口数据缓存机制,以处理连续的屏幕帧数据流。通过固定长度的窗口,高效增删数据,确保低延迟显示和存储。该算法适用于数据压缩、异常检测等场景,保证系统在高负载下稳定运行。 本文转载自:https://www.vipshare.com
132 66
|
1月前
|
存储 算法 C++
【C++数据结构——图】图的邻接矩阵和邻接表的存储(头歌实践教学平台习题)【合集】
本任务要求编写程序实现图的邻接矩阵和邻接表的存储。需掌握带权有向图、图的邻接矩阵及邻接表的概念。邻接矩阵用于表示顶点间的连接关系,邻接表则通过链表结构存储图信息。测试输入为图的顶点数、边数及邻接矩阵,预期输出为Prim算法求解结果。通关代码提供了完整的C++实现,包括输入、构建和打印邻接矩阵与邻接表的功能。
49 10
|
2月前
|
存储 消息中间件 监控
Redis Stream:实时数据流的处理与存储
通过上述分析和具体操作示例,您可以更好地理解和应用 Redis Stream,满足各种实时数据处理需求。
103 14
|
2月前
|
存储 消息中间件 缓存
Redis 5 种基础数据结构?
Redis的五种基础数据结构——字符串、哈希、列表、集合和有序集合——提供了丰富的功能来满足各种应用需求。理解并灵活运用这些数据结构,可以极大地提高应用程序的性能和可扩展性。
58 2
|
3月前
|
传感器 算法
数据结构之环境监测系统(深度优先搜索)
环境监测系统采用深度优先搜索(DFS)算法,实现实时监测和分析环境参数,如温度、湿度等。系统通过构建传感器网络图结构,利用DFS遍历网络,检测异常数据。当温度超过预设阈值时,系统将发出警告。此系统适用于工业生产、室内空调控制、农业温室管理等多种场景,提供高效的环境监测解决方案。
64 12
|
3月前
|
存储 NoSQL 算法
Redis分片集群中数据是怎么存储和读取的 ?
Redis集群采用哈希槽分区算法,共有16384个哈希槽,每个槽分配到不同的Redis节点上。数据操作时,通过CRC16算法对key计算并取模,确定其所属的槽和对应的节点,从而实现高效的数据存取。
84 13
|
3月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
68 5
|
3月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
71 0
|
3月前
|
存储 NoSQL Redis
【赵渝强老师】Redis的存储结构
Redis 默认配置包含 16 个数据库,通过 `databases` 参数设置。每个数据库编号从 0 开始,默认连接 0 号数据库,可通过 `SELECT &lt;dbid&gt;` 切换。Redis 的核心存储结构包括 `dict`、`expires` 等字段,用于处理键值和过期行为。添加键时需指定数据库信息。视频讲解和代码示例详见内容。
|
3月前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
90 0