Redis基础

1 Redis入门

Redis是基于内存的key-value结构数据库

  • 基于内存存储,读写性能高
  • 适合存储热点数据[短时间内有大量的用户访问读取](热点商品,资讯,新闻)
  • 企业应用广泛

1.1 简介

Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。官网: https://redis.io

Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供的数据是可以达到100000+的QPS ( 每秒内查询次数)。它存储的value类型比较丰富,也被称为结构化的NoSq[数据库。

NoSql (Not Only SQL) ,不仅仅是SQL,泛指非关系型数据库。NoSql数据库并不是要取代关系型数据库,而是关系型数据库的补充。

关系型数据库(RDBMS):MySQL、Oracle、DB2、SQLServer
非关系型数据库(NoSql):Redis、Mongo db、MemCached

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

1.2 下载与安装

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

在Windowns系统安装Redis:
直接解压即可使用解压,解压后目录结构如下:
在这里插入图片描述

1.3 Redis服务启动与停止

Linux中Redis服务启动,使用./redis-server,默认端口号为6379,ctrl+c停止Redis服务
修改为后台运行服务器,进入目录 cd /usr/local/redis-4.0.0然后编辑 vim redis.conf
在这里插入图片描述
保存配置后,后台运行服务器src/redis-server ./redis.conf
退出客户端exit
关闭Redis服务./redis.conf shutdown

Windows版启动redis,直接运行radis-server.exe文件和radis-cli.exe文件,Ctrl+C停止Redis服务

1.4 配置密码验证和远程登录

配置密码验证:在redis.conf中配置 requirepass 密码
在这里插入图片描述
设置密码验证后登录后登录服务:src/redis-cli -h localhost -p 6379 -a 123456

允许远程连接,注释掉配置文件中的#bind 127.0.0.1(远程登录注意关闭防火墙)
在这里插入图片描述

2 Redis数据类型

Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型:字符串string、哈希 hash、列表list、集合 set、有序集合 sorted set
在这里插入图片描述

3 Redis常用命令

3.1 字符串string操作命令

SET key value                设置指定key的值
GET key                      获取指定key的值
SETEX key seconds value      设置指定key的值,并将key的过期时间设为seconds秒
SETNX key value              只有在key不存在时设置key的值

更多命令可以参考Redis中文网

3.2 哈希hash操作命令

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
在这里插入图片描述

常用命令:

HSET key field value   将哈希表key中的字段field的值设为value
HGET key field         获取存储在哈希表中指定字段的值
HDEL key field         删除存储在哈希表中的指定字段
HKEYS key              获取哈希表中所有字段
HVALS key              获取哈希表中所有值
HGETALL key            获取在哈希表中指定key的所有字段和值

3.3 列表list操作命令

Redis列表是简单的字符串列表,按照插入顺序排序
在这里插入图片描述

常用命令:

LPUSH key value1 [value2]    将一个或多个值插入到列表头部
LRANGE key start stop        获取列表指定范围内的元素
RPOP key                     移除并获取列表最后一个元素
LLEN key                     获取列表长度
BRPOP key1 [key2 ] timeout   移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止

在头部插入和遍历,在尾部删除。对比队列是在队头删除,队尾插入。
最后插入的元素在遍历时候排第一个。

3.4 集合set操作命令

Redis set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据
在这里插入图片描述

常用命令:

SADD key member1 [member2]   向集合添加一 个或多个成员
SMEMBERS key                 返回集合中的所有成员
SCARD key                    获取集合的成员数
SINTER key1 [key2]           返回给定所有集合的交集
SUNION key1 [key2]           返回所有给定集合的并集
SDIFF key1 [key2]            返回给定所有集合的差集
SREM key member1 [member2]   移除集合中一个或多个成员

3.5 有序集合sorted set操作命令

Redis sorted set有序集合是string类型元素的集合,且不允许重复的成员。每个元素都会关联一个double类型的分数(score)。redis通过分数来为集合中的成员进行从小到大排序。有序集合的成员是唯一的,但分数却可以重复。
在这里插入图片描述
zset底层存储结构:ziplist(压缩列表)或skiplist(跳跃表)。

  • 元素数量小于128个,且每个元素长度小于64字节时使用压缩列表,其他情况使用跳跃表。
  • 压缩列表:本质是一个数组,数组首部存长度、偏移量、元素个数,尾部存结束标识。每个元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个节点保存元素的分值。
  • 跳跃表:单向链表按序保存元素及分值,使用哈希表dict来保存元素和分值的映射关系。链表增加了多级索引,先从最上层索引跳跃查,再渐渐往下层到链表地查询,实现了快速查找元素,时间复杂度O(logn),这种查询算法类似于链表版二分查找,是基于有序的。

zset底层不使用红黑树的原因

  • 范围查找:因为红黑树范围查找效率低,而跳跃表范围查找效率高,因为是链表结构。zset可以用zrange命令查指定范围内元素。
  • 实现难度:跳跃表实现比红黑树简单。

常用命令:

ZADD key score1 member1 [score2 member2]    向有序集合添加一-个或多个成员,或者更新已存在成员的分数
ZRANGE key start stop [WITHSCORES]          通过索引区间返回有序集合中指定区间内的成员
ZINCRBY key increment member                有序集合中对指定成员的分数加上增量increment
ZREM key member [member ....                移除有序集合中的一个或多个成员

3.6 通用命令

KEYS pattern    查找所有符合给定模式( pattern)的key
EXISTS key      检查给定key是否存在
TYPE key        返回key所储存的值的类型
TTL key         返回给定key的剩余生存时间(TTL, time to live),以秒为单位
DEL key         该命令用于在key存在是删除key

可以用Tab键补齐命令

4 在Java中操作Redis

4.1 介绍

  • Redis的Java客户端很多,官方推荐的有三种:Jedis、Lettuce、Redisson

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

4.1 Jedis

  • Jedis的maven坐标: .
<dependency>
	<groupld>redis.clients</groupld>
	<artifactld>jedis</artifactld>
	<version>2.8.0</version>
</dependency>
  • 使用Jedis操作Redis的步骤:①获取连接②执行操作③关闭连接
    在这里插入图片描述

4.3 Spring Data Redis

  • Spring Data Redis中提供了一个高度封装的类:RedisTemplate,针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:
    • ValueOperations: 简单K-V操作
    • SetOperations: set类 型数据操作
    • ZSetOperations: zset类型数据操作
    • HashOperations: 针对map类型的数据操作
    • ListOperations: 针对list类型 的数据操作

SpringBoot整合Redis

  1. 在Spring Boot项目中,可以使用Spring Data Redis来简化Redis操作,maven坐标:
<dependency>
	<groupld>org.springframework.boot</groupld>
	<artifactld>spring-boot-starter-data-redis</ artifactld>
</dependency>

坐标可以在创建模块的时候通过勾选的形式进行选择:
在这里插入图片描述

  1. 配置

默认配置:

spring:
  data:
    redis:
      host: localhost
      port: 6379

其他配置:
在这里插入图片描述

  • 配置信息中的database: 0的意思是使用0号数据库,在redis服务器启动后默认提供了16个数据库,不同数据库内容不互通,默认使用0号数据库。
  • 可以在配置文件redis.conf修改Redis提供数据库数量:databsaes 16 (不建议修改)
  • 在客户端命令行输入select 1可以切换到数据库1
  1. 启动服务器后,自动注入Redis模板对象,获取值操作对象对数据增删改查
    此处使用的是注入Redis模板对象RedisTemplate的opsForValue()方法获取值操作对象ValueOperations ,通过ValueOperations对象的get和set方法操作数据库。
@SpringBootTest
public class SpringDataRedisTest {
    //自动注入RedisTemplate对象
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 操作String类型
     */
    @Test
    public void testString() {
        redisTemplate.opsForValue().set("city123","bj");

        String value = (String) redisTemplate.opsForValue().get("city123");
        System.out.println(value);

        redisTemplate.opsForValue().set("key1","value1",10l, TimeUnit.SECONDS);

        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("city123", "nanjing");//setNX
        System.out.println(aBoolean);//false
    }

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

        //存值
        hashOperations.put("002","name","xiaoli");
        hashOperations.put("002","age","18");
        hashOperations.put("002","addr","beijing");

        //取值
        String name = (String) hashOperations.get("002", "name");
        System.out.println(name);

        //获得hash结构中的所有字段
        Set keys = hashOperations.keys("002");
        for (Object key:keys) {
            System.out.println(key);
        }

        //获得hash结构中的所有值
        List values = hashOperations.values("002");
        for (Object value:values) {
            System.out.println(value);
        }
    }

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

        //存值
        listOperations.leftPush("mylist","a");
        listOperations.leftPushAll("mylist","b","c","d");

        //取值
        List<String> mylist = listOperations.range("mylist", 0, -1);
        for (String value : mylist){
            System.out.println(value);
        }

        //获得列表长度
        Long size = listOperations.size("mylist");
        int lSize = size.intValue();
        for(int i = 0; i < lSize; i++){
            //出队列
            String element = (String) listOperations.rightPop("mylist");
            System.out.println(element);
        }
    }

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

        //存值
        setOperations.add("myset","a","b","c","d","a");

        //取值
        Set<String> myset = setOperations.members("myset");
        for (String o : myset) {
            System.out.println(o);
        }

        System.out.println("======================");
        //删除成员
        setOperations.remove("myset","a","c");
        myset = setOperations.members("myset");
        for (String o : myset) {
            System.out.println(o);
        }
    }

    /**
     * 操做zSet
     */
    @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);

        //取值
        Set<String> myzset = zSetOperations.range("myzset", 0, -1);
        for (String s : myzset) {
            System.out.println(s);
        }

        //修改分数
        zSetOperations.incrementScore("myzset","b",20.0);

        System.out.println("============================");
        //删除元素
        zSetOperations.remove("myzset","a","b");
        myzset = zSetOperations.range("myzset", 0, -1);
        for (String s : myzset) {
            System.out.println(s);
        }
    }

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

        //判断某个key是否存在
        Boolean name = redisTemplate.hasKey("name");

        //删除指定key
        redisTemplate.delete("myset3");

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


在操作redis时,需要先确认操作何种数据,根据数据种类得到操作接口。例如使用opsForValue()获取string类型的数据操作接口,使用opsForHash()获取hash类型的数据操作接口,剩下的就是调用对应api操作了。

序列化器问题

在上述操作过程中,RedisTemplate是以对象为操作的基本单元,存到数据库的实际内容是经过序列化后得到的。
通过命令行看到是乱码的:
在这里插入图片描述

通过配置类修改key的序列化器,由jdk序列化器修改为字符串序列化器:

/**
 * Redis配置类
 */
@Configuration
public class RedisConfig extends CachingConfigurerSupport{
    
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
 
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
 
        //默认的Key序列化器为:JdkSerializationRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
 
        redisTemplate.setConnectionFactory(connectionFactory);
 
        return redisTemplate;
    }
}

测试后可以发现key已经成字符串序列化,而value依然还是jdk序列化,value可以不修改不影响使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值