Redis:Key-Value的NoSQL数据库

 一、非关系型数据库(NoSQL)

介绍

Redis是一款**c语言**开发的、采用key-value数据存储格式的内存级NoSQL数据库,重点关注数据存储格式,是key-value格式,也就是键值对的存储形式。与MySQL数据库不同,MySQL数据库有表、有字段、有记录,Redis没有这些东西,就是一个名称对应一个值,并且数据以存储在内存中使用为主。Redis有它的数据持久化方案,分别是RDB和AOF,但是Redis自身并不是为了数据持久化而生的,主要是在内存中保存数据,加速数据访问的,所以说是一款内存级数据库。非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。

分类

redis(键值数据库)、MongoDB(文档型数据库)、HBase(列式数据库)、Cassandra(宽列数据库)、Neo4J(图形数据库)等。

特点

优点:

1. 格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
2. 速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘。
3. 高扩展性。
4. 成本低:nosql数据库部署简单,基本都是开源软件。

缺点:

1. 不提供sql支持,学习和使用成本较高。
2. 无事务处理。
3. 数据结构相对复杂,复杂查询方面稍欠。

  Redis使用场景

- 数据库
- 缓存
- 任务队列
- 消息队列
- 分布式锁 

 二、Redis数据类型及操作

1. 数据类型

2. 通用命令

命令 介绍
KEYS parrern 查找所有符合给定模式(pattern)的可以。例如:keys * 获取所有的key。
EXISTS key 检查key是否存在
TYPE key 返回key所存储值的类型
EXPIRE key key设置有效期,有效期到期时该key会被自动删除
TTL key 返回key的剩余生存时间,秒为单位。TTL:time to live
DEL key 删除存在的key

 3. 字符串类型string

命令 描述
SET key value 添加键值对或修改指定key的值
GET key 获取key的值
MSET key1 value1 key2 value2 ... 批量添加多个键值对
MGET key1 key2 ... 根据多个key获取对应的值
INCR key 指定key的值+1
INCRBY key n 指定key的值+n
SETNX key value key不存在时添加
SETEX key seconds value 添加键值对同时为key指定存活时间

4. hash类型 

  • Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。

  • string的数据存储是一个名称对应一个值,如果要维护的数据过多,可以使用hash哈希存储模型它一个名称下可以存储多个数据每个数据也可以有自己的二级存储名称

命令 描述
HSET key field value 添加或修改
HGET key field 获取指定key中filed对应的值
HDEL key fileld 删除指定key中f指定的filed
HKEYS key 获取指定key中所有filed
HVALS key 获取指定key中所有value
HGETALL 获取指定key中所有filed和value
HSETNX 指定key中filed不存在时添加

 5. list类型

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。 

命令 描述
LPUSH key value1 value2 ... 左侧插入一个或多个元素
LPOP key 移除并返回列表左侧的第一个元素,没有则返回nil
RPUSH key value1 value2 ... 右侧插入一个或多个元素
RPOP key 移除并返回列表右侧的第一个元素,没有则返回nil
LLEN key 获取列表长度
LRANGE key start stop 获取指定范围内的元素(0,-1)可以获取所有元素
BLPOP key timeout 移出并获取列表左侧的第一个元素, 如果列表没有元素 会阻塞列表直到等待超时或发现可弹出元素为止
BRPOP key timeout 移出并获取列表右侧的第一个元素, 如果列表没有元素 会阻塞列表直到等待超时或发现可弹出元素为止

6. set类型 

Redis 的 set 是 string 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。 

命令 描述
SADD key member1 member2 ... 向集合添加一个或多个成员
SREM key member1 member2 ... 移除集合中一个或多个成员
SMEMBERS key 返回集合中的所有成员
SCARD key 获取集合的成员数
SISMEMBER key member 判断 member 元素是否是集合 key 的成员
SDIFF key1 key2 ... 返回第一个集合与其他集合之间的差异
SINTER key1 key2 ... 返回给定所有集合的交集
SUNION key1 key2 ... 返回所有给定集合的并集

 7. sorted set类型

Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

命令 描述
ZADD key score1 member1 score 2member2 ... 向有序集合添加一个或多个成员,或者更新已存在成员的分数
ZREM key member1 member2 ... 移除有序集合中的一个或多个成员
ZCARD key 获取有序集合的成员数
ZCOUNT key min max 计算在有序集合中指定区间分数的成员数
ZRANGE key start stop 通过索引区间返回有序集合指定区间内的成员
ZSCORE key member 返回有序集中,成员的分数值
ZRANGEBYSCORE key min max 通过分数返回有序集合指定区间内的成员
ZRANK key member 返回有序集合中指定成员的索引
ZREVRANK key memeber 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序

 注意:所有的排名默认都是升序,如果要降序则在命令的最后面添加REV

  • 升序获取sorted set 中的指定元素的排名:ZRANK key member。

  • 降序获取sorted set 中的指定元素的排名:ZREVRANK key memeber。

底层存储结构 

- zset:ziplist(压缩列表)或skiplist(跳跃表)。

- 元素数量小于128个,且每个元素长度小于64字节时使用压缩列表,其他情况使用跳跃表。

1.压缩列表:本质是一个数组,数组首部存长度、偏移量、元素个数,尾部存结束标识。每个元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个节点保存元素的分值。

 2.跳跃表:单向链表按序保存元素及分值,使用哈希表dict来保存元素和分值的映射关系。链表增加了多级索引,先从最上层索引跳跃查,再渐渐往下层到链表地查询,实现了快速查找元素,时间复杂度O(logn),这种查询算法类似于链表版二分查找,是基于有序的。

 

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

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

  • 实现难度:跳跃表实现比红黑树简单。

三、springboot整合redis 

Spring Data Redis(Spring官网)

Spring Data Redis中提供了一个高度封装的类:RedisTenplate,将同一类型操作封装为operation接口:

1. ValueOperations:操作简单字符串key-value。
2. SetOperations:操作set类型。
3. ZSetOperations:操作sortedSet类型。
4. HashOperations:操作hash类型。
5. ListOperations:操作list类型。

导入依赖 

<!-- redis启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce连接池需要的依赖 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

 创建项目时也可以勾选自动导入redis启动器。

  配置redis

基本配置
spring:
  redis:
  	# redis的ip
    host: 192.168.93.128
    # redis的端口号
    port: 6379
    # redis的密码
    password: 123456
更多配置
spring:
  redis:
    host: 192.168.93.128    #redis的ip
    port: 6379              #redis的端口号
    password: 123456        #redis的密码
    database: 0             #操作redis几号库
    timeout: 5000           #读取超时时间
    connect-timeout: 10000  #连接超时时间
    lettuce:                #lettuce连接池配置
      pool:
        enabled: true       #开启连接池
        max-active: 10      #最大连接数
        max-idle: 4         #最大空闲连接
        min-idle: 0         #最小空闲连接
        max-wait: -1        #最大连接阻塞等待时间,过该时间仍无法获取连接则抛出异常 -1没有限制
        time-between-eviction-runs: -1  #关闭空闲时间超过指定时间的连接

使用RedisTemplate

@SpringBootTest
class RedisApplicationTests {
    @Autowired
    RedisTemplate redisTemplate;
    @Test
    void testString() {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("id","1");
        Object name = valueOperations.get("id");

        System.out.println(name);
        valueOperations.getAndExpire("id",Duration.ofSeconds(10));

        DataType dataType = redisTemplate.type("id");
        System.out.println(dataType);

        Long l = redisTemplate.getExpire("id");
        System.out.println(l);
    }

    @Test
    void testList(){
        ListOperations<String,String> listOperations = redisTemplate.opsForList();
        listOperations.leftPush("names","zs");
        listOperations.rightPush("names","ls");

        List<String> list = listOperations.range("names",-1);
        System.out.println(list);
    }

    @Test
    void testHash(){
        HashOperations<String,Object,Object> hashOperations = redisTemplate.opsForHash();
        hashOperations.put("user","id","1");
        hashOperations.put("user","name","ls");

        Map<Object,Object> user = hashOperations.entries("user");
        System.out.println(user);
    }
}

 RedisTemplate序列化器问题

RedisTemplate是以对象为操作的基本单元,存到数据库的实际内容是序列化后的。

@SpringBootTest
class RedisApplicationTests {
    @Autowired
    RedisTemplate redisTemplate;

    @Test
    void testString() {
        /* 设置key-value 序列化器 */
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("id","1");
    }

使用StringRedisTemplate

  • StringRedisTemplate是以字符串为操作的基本单元。命令行客户端redis-cli.exe默认使用StringRedisTemplate。

  • 为了方便使用基于字符串为数据的操作,springboot整合redis时提供了专用的API接口StringRedisTemplate。

  • RedisTemplate是以对象为操作的基本单元,存到数据库的实际内容是序列化后的。

@SpringBootTest
class RedisApplicationTests {
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Test
    void testString() {
        ValueOperations<String,String> valueOperations = stringRedisTemplate.opsForValue();
        valueOperations.set("sid","1");
    }

    @Test
    void testList(){
        ListOperations<String,String> listOperations = stringRedisTemplate.opsForList();
        listOperations.leftPush("snames","zs");
        listOperations.rightPush("snames","ls");
    }

  springboot使用jedis客户端整合redis

springboot整合redis技术提供了多种客户端兼容模式,默认提供的是lettucs客户端技术,也可以根据需要切换成指定客户端技术,例如jedis客户端技术。jedis是Redis传统的客户端技术。

<!-- redis启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- jedis依赖 -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
配置redis
基本配置
spring:
  redis:
    host: 192.168.93.128    #redis的ip
    port: 6379              #redis的端口号
    password: 123456        #redis的密码
更多配置
spring:
  redis:
    host: 192.168.93.128    #redis的ip
    port: 6379              #redis的端口号
    password: 123456        #redis的密码
    database: 0             #操作redis几号库
    timeout: 5000           #读取超时时间
    connect-timeout: 10000  #连接超时时间
    jedis:                  #jedis连接池配置
      pool:
        enabled: true       #开启连接池
        max-active: 10      #最大连接数
        max-idle: 4         #最大空闲连接
        min-idle: 0         #最小空闲连接
        max-wait: -1        #最大连接阻塞等待时间,-1表示没有时间限制
        time-between-eviction-runs: -1  #关闭空闲时间超过指定时间的连接
 lettcus与jedis区别
  • lettcus基于Netty框架进行与Redis服务器连接,底层设计中采用StatefulRedisConnection。 StatefulRedisConnection自身是线程安全的,可以保障并发访问安全问题,所以一个连接可以被多线程复用。lettcus也支持多连接实例一起工作。

  • jedis连接Redis服务器是直连模式,当多线程模式下使用jedis会存在线程安全问题,解决方案可以通过配置连接池使每个连接专用,这样整体性能就大受影响。

四、Spring Cache 

redis使用较多的使用场景为缓存。

Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。

Spring Cache提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。

缓存: 缓存是一种介于数据永久存储介质与应用程序之间的数据临时存储介质,使用缓存可以有效的减少低速数据读取过程的次数(例如磁盘IO),提高系统性能。此外缓存不仅可以用于提高永久性存储介质的数据读取效率,还可以提供临时的数据存储空间。而springboot提供了对市面上几乎所有的缓存技术进行整合的方案。

 常用注解 

SpringBoot内置缓存Simple 

 引入依赖
<!-- 缓存启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
启动类开启缓存
@SpringBootApplication
//开启缓存功能
@EnableCaching
public class SpringbootCacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootCacheApplication.class,args);
    }
}
 设置操作的数据是否使用缓存

使用@Cacheable注解后,执行当前操作,如果发现对应名称在缓存中没有数据,就正常读取数据,然后放入缓存;如果对应名称在缓存中有数据,就终止当前业务方法执行,直接返回缓存中的数据。

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookMapper bookMapper;
    //Cacheable译为可缓存的,可缓冲的。@Cacheable的value属性是存储空间名,key属性是此方法返回值在存储空间内的键名。
    //key属性名必须和形参名一样才能缓存,别忘了#号。 多个参数可以使用拼接方式:"#id+'_'+#name"。
    @Cacheable(value="BookServiceGetById",key="#id")
    public Book getById(Integer id) {
        return bookMapper.selectById(id);
    }
}

注意:

  • 一定一定别忘了#号。

  • 缓存的key属性名必须方法的形参名一样才能缓存。 只要此key对应的缓存已存在,下次不管查询出什么数据,返回的结果都是直接从缓存的这个key里取。

  • 被注解@Cacheable声明的方法不能被本类中其他方法调用,原因是spring容器管理问题。

SpringBoot整合Redis缓存 

引入依赖
<!-- 缓存启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<!-- redis启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- 使用lettucs连接池需要引入 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
配置
spring:
  redis:
    port: 6379
    host: 192.168.93.128
    password: 123456
  cache:
    type: redis

相关文章

文章浏览阅读752次。关系型数据库关系型数据库是一个结构化的...
文章浏览阅读687次,点赞2次,收藏5次。商城系统中,抢购和秒...
文章浏览阅读1.4k次。MongoTemplate开发spring-data-mongodb...
文章浏览阅读887次,点赞10次,收藏19次。1.背景介绍1. 背景...
文章浏览阅读819次。MongoDB连接失败记录_edentialmechanisn...
文章浏览阅读470次。mongodb抽取数据到ES,使用ELK内部插件无...