【Redis】一篇入门Redis

Redis简介

Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存、消息中间件。
官网:Redis官网
Redis图片
Redis是用C语言开发的一个高性能键值对(key-value)数据库,他存储的value类型比较丰富,也被成为结构化NoSql数据库。
NoSql(Not Only SQL),不仅仅是SQL,泛指非关系型数据库。NoSql数据库并不是要取代关系型数据库,而是关系型数据库的补充。

  • 关系型数据库(RDBMS): Mysql、Oracal、DB2、SQLServer

  • 非关系型数据库(NoSql): Redis、Mongo db、MemCached

  • Redis应用场景: 缓存、任务队列、消息队列、分布式锁


Redis下载与安装

Redis安装包分为windows版和Linux版

在Linux系统安装Redis步骤:
1、将Redis安装包上传到Linux
2、解压安装包,命令:tar -zxvf redis-4.0.0.tar.gz -C /usr/local
3、安装Redis的依赖环境gcc,命令:yum install gcc-c++
4、进入/usr/local/redis-4.0.0,进行编译,命令:make
5、进入Redis的src目录,进行安装,命令:make install

Redis的Windows版属于绿色软件,直接解压即可使用
Redis解压后目录结构


Redis服务启动与停止

Linux环境中Redis服务启动,可以使用redis-server,切换到Redis的src目录,使用命令:./redis-server,默认端口号是6379,Ctrl + C 停止Redis服务。

Windows环境中Redis服务启动,直接点击redis-server.exe,默认端口号为6379,,Ctrl + C 停止Redis服务,如下:
Redis服务端启动页面

客户端点击redis-cli.exe,如下:
Redis客户端启动页面


Redis数据类型

Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型:

  • 字符串 string
  • 哈希 hash
  • 列表 list
  • 集合 set
  • 有序集合 sorted set
    Redis常用数据类型

更多Redis命令详见:Redis中文网

字符串 string 操作命令

字符串 string 操作命令

哈希 hash 操作命令

哈希 hash 操作命令

列表 list 操作命令

列表 list 操作命令

集合 set 操作命令

集合 set 操作命令

有序集合 sorted set 操作命令

有序集合 sorted set 操作命令

通用命令

通用命令


Java操作Redis

介绍

Redis 的 Java 客户端很多,官方推荐的有三种:

  • Jedis
  • Lettuce
  • Redisson

Spring 对 Redis 客户端进行了整合,提供了 Spring Data Redis,在SpringBoot项目中还提供了对应的starter,即spring-boot-starter-redis

Jedis

Jedis的maven坐标:

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

使用Jedis操作Redis的步骤:

  1. 获取连接
  2. 执行操作
  3. 关闭连接

第一步:新建Maven工程,导入以下依赖:

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

<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
</dependency>

第二步:在测试中编写如下代码:

/**
 * 使用Jedis操作Redis
 * API和指令同名,自行测试
 */
public class JedisTest {

    @Test
    public void testRedis(){
        // 1、获取连接(保证Redis服务是启动的)
        Jedis jedis = new Jedis("localhost",6379);

        // 2、执行具体的操作
        String s = jedis.set("username", "test_limou");

        System.out.println(s); // 输出OK
        
        Set<String> keys = jedis.keys("*");
        for (String key : keys) {
            System.out.println(key);
        }

        // 3、关闭连接
        jedis.close();
    }

}

Spring Data Redis

Spring Data Redis 中提供了一个高度封装的类:RedisTemplate,针对Jedis客户端中大量api进行了归类,将同一类型的操作封装为operation接口,具体分类如下:

  • ValueOperations:简单K-V操作
  • SetOperations:set类型数据操作
  • ZSetOperations:zset类型数据操作
  • HashOperations:针对map类型的数据操作
  • ListOperations:针对list类型的数据操作

在 SpringBoot 项目中。可以使用Spring Data Redis 来简化Redis操作,maven坐标如下:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

快速上手Spring Data Redis
1、创建springboot工程,引入依赖(我这里springboot版本2.4.5):

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

2、配置application.yml文件

spring:
  application:
    name: springdataredis_demo

  # Redis相关配置
  redis:
    host: localhost
    port: 6379
    # password: xxx
    database: 0
    jedis:
      # Redis连接池配置
      pool:
        max-active: 8 # 最大连接数
        max-wait: 1ms # 连接池最大阻塞等待时间
        max-idle: 4 # 连接池中的最大空闲连接
        min-idle: 0 # 连接池中最小空闲连接

3、编写测试类,测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class SpringDataRedisTest {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 操作String类型数据
     */
    @Test
    public void testString(){
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("city", "shanxi");

        // 这时候再去key * 查看所有key的时候,会发现我们设置的key 并不是 city
        // 而是:\xac\xed\x00\x05t\x00\x04city ,这样一串字符
        // 这是因为这里设置key的时候是采用默认的方式将key序列化后存入数据库的
        // 我们可以通过编写Redis配置类,修改默认序列化方式
        // 在编写完配置类后,测试发现key:city 正常添加,但是value:\xac\xed\x00\x05t\x00\x06shanxi
        // 这是因为配置类中并没有修改value的序列化方式
        // 一般也不对value进行修改,当我们在程序中再去获取value值时,它会反序列化为正常值:shanxi
        String value = (String) valueOperations.get("city");
        System.out.println(value); // shanxi

        valueOperations.set("key1", "value1", 10L, TimeUnit.SECONDS); // 10s过期

        Boolean flag = valueOperations.setIfAbsent("city", "yulin"); // 如果有就设置,对应返回布尔值
        System.out.println(flag);
    }
}

4、Redis配置类如下:

/**
 * Redis配置类
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();

        // 默认的Key序列化器为:JdkSerializationRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        redisTemplate.setConnectionFactory(redisConnectionFactory);

        return redisTemplate;
    }
}

以下内容是个人练习使用的API,大家也可以自行测试:

@SpringBootTest
@RunWith(SpringRunner.class)
public class SpringDataRedisTest {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 操作String类型数据
     */
    @Test
    public void testString() {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("city", "shanxi");

        // 这时候再去key * 查看所有key的时候,会发现我们设置的key 并不是 city
        // 而是:\xac\xed\x00\x05t\x00\x04city ,这样一串字符
        // 这是因为这里设置key的时候是采用默认的方式将key序列化后存入数据库的
        // 我们可以通过编写Redis配置类,修改默认序列化方式
        // 在编写完配置类后,测试发现key:city 正常添加,但是value:\xac\xed\x00\x05t\x00\x06shanxi
        // 这是因为配置类中并没有修改value的序列化方式
        // 一般也不对value进行修改,当我们在程序中再去获取value值时,它会反序列化为正常值:shanxi
        String value = (String) valueOperations.get("city");
        System.out.println(value); // shanxi

        valueOperations.set("key1", "value1", 10L, TimeUnit.SECONDS); // 10s过期

        Boolean flag = valueOperations.setIfAbsent("city", "yulin"); // 如果有就设置,对应返回布尔值
        System.out.println(flag);
    }

    /**
     * 操作Hash类型数据
     */
    @Test
    public void testHash() {
        HashOperations hashOperations = redisTemplate.opsForHash();

        // 存数据
        hashOperations.put("dog", "name", "大黄");
        hashOperations.put("dog", "food", "骨头");
        hashOperations.put("dog", "age", "6");

        // 取数据
        String name = (String) hashOperations.get("dog", "name");
        String food = (String) hashOperations.get("dog", "food");
        String age = (String) hashOperations.get("dog", "age");

        System.out.println(name + " / " + food + " / " + age);

        // 获得hash结构所有字段
        Set dog = hashOperations.keys("dog");
        for (Object o : dog) {
            System.out.println(o); // name、food、age
        }

        // 获得hash结构所有值
        List dogValues = hashOperations.values("dog");
        for (Object dogValue : dogValues) {
            System.out.println(dogValue); // 大黄、骨头、6
        }
    }

    /**
     * 操作List类型数据(存取类似队列)
     */
    @Test
    public void testList() {
        ListOperations listOperations = redisTemplate.opsForList();

        // 存数据(有序,可重复)
        listOperations.leftPush("mylist", "a"); // 存一个
        listOperations.leftPushAll("mylist", "b", "c", "d", "a"); // 存多个

        // 取数据
        List mylist = listOperations.range("mylist", 0, -1);// 取所有元素
        for (Object o : mylist) {
            System.out.println(o);
        }

        // 获得列表长度
        Long sizeLong = listOperations.size("mylist");
        int size = sizeLong.intValue();

        for (int i = 0; i < size; i++) {
            // 出队列
            Object element = listOperations.rightPop("mylist");
            System.out.println((i + 1) + " 移出--> " + element);
        }
    }

    /**
     * 操作Set类型数据
     */
    @Test
    public void testSet() {
        SetOperations setOperations = redisTemplate.opsForSet();

        // 存数据(无序、不可重复)
        setOperations.add("myset-java", "a", "b", "c", "a");

        // 取数据
        Set myset = setOperations.members("myset-java");
        for (Object o : myset) {
            System.out.println(o);
        }

        // 删数据
        Long remove = setOperations.remove("myset-java", "a", "b");
        System.out.println("remove: " + remove);

        // 取数据
        Set myset2 = setOperations.members("myset-java");
        for (Object o : myset2) {
            System.out.println(o);
        }
    }

    /**
     * 操作ZSet类型的数据,SortedSet(有序集合,根据分数排序从小到大)
     */
    @Test
    public void testZSet() {
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();

        // 存数据
        zSetOperations.add("myZSet", "a", 10.0);
        zSetOperations.add("myZSet", "b", 11.0);
        zSetOperations.add("myZSet", "c", 12.0);
        zSetOperations.add("myZSet", "a", 13.0); // 覆盖掉上边的a

        // 取数据
        Set myZSet = zSetOperations.range("myZSet", 0, -1);
        for (Object o : myZSet) {
            System.out.println(o);
        }
        System.out.println("==========");

        // 修改分数
        zSetOperations.incrementScore("myZSet", "b", 20.0); // 为指定元素增加分数

        // 取数据
        myZSet = zSetOperations.range("myZSet", 0, -1);
        for (Object o : myZSet) {
            System.out.println(o);
        }
        System.out.println("==========");

        // 删除元素
        zSetOperations.remove("myZSet", "a", "b");

        // 取数据
        myZSet = zSetOperations.range("myZSet", 0, -1);
        for (Object o : myZSet) {
            System.out.println(o);
        }
    }
    
    /**
     * 通用操作,针对不同的数据类型都可以操作
     */
    @Test
    public void testCommon(){
        // 获取Redis中所有的key
        Set keys = redisTemplate.keys("*");
        for (Object key : keys) {
            System.out.println(key);
        }
        System.out.println("=============");

        // 判断某个key是否存在
        Boolean flagExists = redisTemplate.hasKey("myset");
        System.out.println(flagExists);
        System.out.println("=============");

        // 删除指定key
        Boolean flagDelete = redisTemplate.delete("myset");
        System.out.println(flagDelete);
        System.out.println("=============");

        // 获取指定key对应的value数据类型
        DataType type = redisTemplate.type("myset-java");
        System.out.println(type.name());
    }
}

项目中碰到的情况

1、缓存短信验证码(登录)

在发送验证码的方法中,将随机生成的验证码缓存到Redis中,并设置有效期5min

// 用redis存储,并且设置有效期5min
redisTemplate.opsForValue().set(phone, code, 5L, TimeUnit.MINUTES);

在后续登录方法中,直接从Redis中获取缓存的验证码

// 从redis中获取验证码
String codeInRedis = redisTemplate.opsForValue().get(phone);

登录成功直接删除Redis中的验证码

// 如果用户登录成功,删除Redis中缓存的验证码
redisTemplate.delete(phone);

2、缓存菜品数据

在高并发的情况下,频繁查询数据库会导致系统性能下降,服务端响应时间增长,用Redis做缓存优化,提高系统性能。

首先想法是用菜品的分类Id作为Key,用当前分类下的菜品集合作为Value

1、当我们去查询菜品的时候,首先从Redis中去获取菜品的数据,如果有直接返回,如果没有就去查询数据库,之后将查询到的菜品数据以及当前菜品分类的Id存入Redis中。

2、同时要注意在操作分类的新增更新方法时候,去更新Redis内该分类Key对应的菜品Value值 ,根据分类的Id去清除缓存
注意:在使用缓存过程中,要注意保证数据库中数据和缓存中数据一致,如果数据库中的数据发生变化,需要及时清理缓存数据。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宫野琦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值