前言

传统(企业内部)软件:         比如工单系统、OA、CRM、ERP、CMDB、大学选课系统等,主要服务于企业内部用户群体

互联网软件:                  比如 微信、QQ、今日头条、抖音、优酷、百度、微信、京东、天猫、12306等,可服务于广大互联网用户群体

互联网软件有以下3大突出特点:

  • 高并发(同时访问量大)
  • 高可用(网站任何时候都能访问)
  • 海量数据(动态数据量大)

MySQL支持最大并发是2000/秒,如果我们把所有数据存储在MySQL中,单靠关系型数据库,无法支撑起1个互联网软件

由于互联网的这些特点,单纯的关系型数据库是扛不住的,那么这个时候就需要非关系型数据库的加入;

非关系型数据库是为了配合关系型数据库共同应对互联网产品问题而存在的,他们之间的关系是合作,而不是替代;

常见的NoSQL产品:

  • Redis
  • Mongodb

 

一、Redis介绍

Redis(Remote Dictionary Server)是用C语言开发的一个开源的高性能的键值对数据库。

它的所有数据都是保存在内存中的,这也就决定了其读写速度之快,是其它硬盘保存数据的系统所无法匹敌的。

官方曾经给出过一组测试数据,50个并发执行100000个请求: 读的速度是110000次/s,写的速度是81000次/s。

正是由于其有着如此高的性能,所以Redis在企业中最大的一个应用是作为缓存服务器使用,当然它也可以作为数据存储和消息中间件来用。

 

二、Redis常用命令

 Redis采用键值对存储数据,键的类型只能是字符串,值支持5种数据类型;

  • 字符串:   普通字符串
  • hash:      适合存储对象
  • 列表:      有序可以重复
  • 集合:    无序不重复
  • 有序集合:有序不重复

1.String 字符串

字符串类型是Redis中最为基础的数据存储类型。

增加数据:set key value

127.0.0.1:6379> set name zhanggen
OK

获取数据:get key

127.0.0.1:6379> get name
"zhanggen"
127.0.0.1:6379> 

删除数据:del key

127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> get name
(nil)

增加数据的时候设置有效时间:setex key 存活时间(单位是s) value

127.0.0.1:6379> setex name 5 zhanggen
OK
127.0.0.1:6379> get name
"zhanggen"
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> 

增加的时候判断key是否存在:setnx key value

127.0.0.1:6379> setnx name Martin
(integer) 1
127.0.0.1:6379> get name
"Martin"
127.0.0.1:6379> 

自增(减)操作:

incr/decr key 

127.0.0.1:6379> set age 19
OK
127.0.0.1:6379> incr age
(integer) 20
127.0.0.1:6379> decr age
(integer) 19
127.0.0.1:6379> 

incrby/decrby key step

127.0.0.1:6379> incrby age 3
(integer) 22
127.0.0.1:6379> decrby age 3
(integer) 19
127.0.0.1:6379> 

 

2.Hash 哈希

Hash类型极其类似于Java中的Map,值里面可以存放一组组的键值对,该类型非常适合于存储对象类型的信息。

增加数据:hset key hkey hvalue

127.0.0.1:6379> hset student1 name zhanggen
(integer) 1
127.0.0.1:6379> hset student1 age 18
(integer) 1
127.0.0.1:6379> hset student1 sex man
(integer) 1

获取数据:hget key hkey

127.0.0.1:6379> hget student1 name
"zhanggen"
127.0.0.1:6379> hget student1 age
"18"
127.0.0.1:6379> hget student1 sex
"man"
127.0.0.1:6379> 

获取hash的所有键hkey:hkeys key

127.0.0.1:6379> hkeys student1
1) "name"
2) "age"
3) "sex"

获取hash所有值hvalue: hvals key

127.0.0.1:6379> hvals student1
1) "zhanggen"
2) "18"
3) "man"
127.0.0.1:6379> 

删除数据(单个): hdel key hkey

127.0.0.1:6379> hdel student1 sex
(integer) 1
127.0.0.1:6379> hkeys student1
1) "name"
2) "age"

删除数据(所有): del key

127.0.0.1:6379> del student1
(integer) 1
127.0.0.1:6379> hkeys student1
(empty array)
127.0.0.1:6379> 

 

3.List 列表

List类型底层是一个双向字符串链表,里面的元素是有序可重复的,我们可以从链表的任何一端进行元素的增删

添加数据:lpush(rpush) key value

127.0.0.1:6379> lpush list zhanggen
(integer) 1
127.0.0.1:6379> lpush list lisi
(integer) 2
127.0.0.1:6379> rpush list wangwu

查询数据:lrange key [开始索引 结束索引]

127.0.0.1:6379> lrange list 0 -1
1) "lisi"
2) "zhanggen"
3) "wangwu"

列表长度:llen key

127.0.0.1:6379> llen list
(integer) 1

删除数据:lpop(rpop) key value

127.0.0.1:6379> lpop list
"lisi"
127.0.0.1:6379> rpop list
"wangwu"

移出并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止:BRPOP key timeout

 

4.Set 集合

Set类型底层是一张hash表,里面的元素是无序的,不可重复的。

添加数据:sadd key value

127.0.0.1:6379> sadd userList zhangsan
(integer) 1
127.0.0.1:6379> sadd userList lisi
(integer) 1
127.0.0.1:6379> sadd userList wangwu

查看数据:smembers key

127.0.0.1:6379> smembers userList
1) "zhangsan"
2) "wangwu"
3) "lisi"

获取元素数量:scard key

127.0.0.1:6379> scard userList
(integer) 3
127.0.0.1:6379> 

移除集合元素:srem key value

127.0.0.1:6379> srem userList lisi
(integer) 1
127.0.0.1:6379> smembers userList
1) "zhangsan"
2) "wangwu"
127.0.0.1:6379> 

 

求集合的交集(intersection):sinter key1 key2 

127.0.0.1:6379> sadd list1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd list2 1 2 5 6 
(integer) 4127.0.0.1:6379> SINTER list1 list2
1) "1"
2) "2"

求集合的并集:sunion key1 key2

127.0.0.1:6379> SUNION list1 list2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"

求集合的差集:sdiff key1 key2

127.0.0.1:6379> sdiff list1 list2
1) "3"
2) "4"
127.0.0.1:6379> 

 

5.ZSet 有序集合

ZSet,也称sortedSet,在Set的基础上,加入了有序功能,在添加元素的时候,允许指定一个分数,它会按照这个分数排序。

添加数据:zadd key score value

127.0.0.1:6379> zadd manList 10 zhanggen
(integer) 1
127.0.0.1:6379> zadd manList 20 zhanggen1
(integer) 1
127.0.0.1:6379> zadd manList 30 zhanggen2
(integer) 1

查询数据:zrange key [开始索引 结束索引]

127.0.0.1:6379> zrange manList 0 -1
1) "zhanggen"
2) "zhanggen1"
3) "zhanggen2"

查询数据并根据score排序

127.0.0.1:6379> zrange manList 0 -1 withscores
1) "zhanggen"
2) "10"
3) "zhanggen1"
4) "20"
5) "zhanggen2"
6) "30"
127.0.0.1:6379> 

删除数据:zrem key value

127.0.0.1:6379> zrem manList zhanggen2
(integer) 1

 

6.通用命令

通用命令指的是不受数据类型限制的一批命令

1. 模糊查询键:keys 模糊匹配规则

127.0.0.1:6379> keys list*
1) "list1"
2) "list2"
3) "list"

2. 根据键判断记录是否存在:exists key

127.0.0.1:6379> exists a
(integer) 0
127.0.0.1:6379> exists list1
(integer) 1
127.0.0.1:6379> 

3. 根据键判断值类型:type key

127.0.0.1:6379> type list1
set
127.0.0.1:6379> 

4. 返回key的剩余生存时间:TTL key

返回-2表示当前key已经过期;

127.0.0.1:6379> setex name 5 wangge
OK
127.0.0.1:6379> ttl name
(integer) 3
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379> ttl name
(integer) -2

5. 选择数据库: select 库索引[从0开始]

127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> setex name 3 zhangyu
OK

6. 清空当前数据库: flushdb

127.0.0.1:6379[3]> flushdb
OK127.0.0.1:6379[3]> keys *
(empty array)

7. 清空所有数据库: flushall 

127.0.0.1:6379[3]> flushall
OK
127.0.0.1:6379[3]> keys *
(empty array)
127.0.0.1:6379[3]> select 1
OK127.0.0.1:6379[1]> keys *
(empty array)
127.0.0.1:6379[1]> 

 

三、Java操作Redis

如何使用Java程序连接Redis

1.Jedis

Redis作为一款优秀的缓存服务器存在,大多数语言都提供了连接Redis的驱动包,在Java中,比较出名的是Jedis。

1.1.引入Pom依赖 

<dependencies>
        <!--加入jedis依赖-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.3</version>
        </dependency>
        <!--加入单元测试依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

1.2.代码测试

package com.zhanggen.test;

import org.junit.After;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.List;
import java.util.Set;

public class JedisTest1 {
    //1.创建Jedis客户端
    private Jedis jedis = new Jedis("192.168.56.18", 6379);

    @Test
    public void testString() {
        //2.使用Jedis客户端操作String
        jedis.setex("name", 6, "张根");
        String name = jedis.get("name");
        System.out.println(name);
    }

    @Test
    public void testList() {
        //2.使用Jedis客户端操作list
        jedis.lpush("userList", "张弢", "张启樵", "张三丰", "张无忌");
        List<String> userList = jedis.lrange("userList", 0, -1);
        for (String user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testHash() {
        //2.使用Jedis客户端操作hash
        jedis.hset("user", "name", "张根");
        jedis.hset("user", "age", "18");
        String name = jedis.hget("user", "name");
        String age = jedis.hget("user", "age");
        System.out.println(name);
        System.out.println(age);
    }

    @Test
    public void testSet() {
        //2.使用Jedis客户端操作集合set
        jedis.sadd("name", "Martin");
        jedis.sadd("name", "Jack");
        jedis.sadd("name", "Tom");
        Set<String> userList = jedis.smembers("name");
        for (String user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testZset() {
        //2.使用Jedis客户端操作有序集合Zset
        jedis.zadd("programingLanguages", 1, "C");
        jedis.zadd("programingLanguages", 2, "C++");
        jedis.zadd("programingLanguages", 3, "Java");
        jedis.zadd("programingLanguages", 0, "Python");
        Set<String> programingLanguages = jedis.zrange("programingLanguages", 0, -1);
        for (String language : programingLanguages) {
            System.out.println(language);
        }

    }


    @After
    public void colseRedis() {
        ;
        //3.关闭客户端
        jedis.close();
        System.out.println("关闭Redis成功");
    }
}

 

2.SpringDataRedis

Spring是用于开发企业级Web应用的框架,这个框架由很多子项目组成,之前我们学习了Spring框架中的JDBC、MVC和Boot;

SpringData也是Spring框架下的1个子项目,主要封装了持久层的解决方案;

SpringDataRedis是SpringData子项目下1个子项目;

SpringDataRedis对Redis底层开发包进行了高度封装,提供了一个高度封装的类:RedisTemplate,用于操作Redis各种数据类型。

  • ValueOperations:简单K-V操作

  • SetOperations: set类型数据操作

  • ZSetOperations: zset类型数据操作

  • HashOperations: 针对hash类型的数据操作

  • ListOperations: 针对list类型的数据操作

 

2.1.环境准备

2.1.1.创建SpringBoot工程

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.5</version>
            </plugin>
        </plugins>
    </build>
pom.xml

2.1.2.SpringBoot配置文件

spring:
  redis:
    host: 192.168.56.18  #redis服务器的IP
    port: 6379
    database: 0 # 操作的是0号数据库
    jedis: #Redis连接池配置
      pool:
        max-active: 8 #最大连接数
        max-wait: 1ms #连接池最大阻塞等待时间
        max-idle: 4 #连接池中的最大空闲连接
        min-idle: 0 #连接池中的最小空闲连接
application.yaml

2.1.3.创建主类

package com.zhanggen;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RedisApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class, args);
    }
}
RedisApplication.java

2.1.4.提供配置类

package com.zhanggen.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

//Redis配置类
//当前配置类不是必须的,因为 Spring Boot 框架会自动装配 RedisTemplate 对象,
//但是默认的key序列化器为JdkSerializationRedisSerializer,导致我们存到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());

        //设置value的序列化器   默认是JdkSerializationRedisSerializer
        //redisTemplate.setValueSerializer(new StringRedisSerializer());
        //redisTemplate.setHashValueSerializer(new StringRedisSerializer());

        //为了解决数字自增问题
        //redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        redisTemplate.setConnectionFactory(connectionFactory);

        return redisTemplate;
    }
}
RedisConfig.java

2.1.5.提供测试类

package com.zhanggen.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.TimeUnit;

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

    @Autowired
    private RedisTemplate redisTemplate;


    @Test
    public void testString() {
        ValueOperations ops = redisTemplate.opsForValue();
        //增加数据
        ops.set("1001", "张三");
        ops.set("1002", "李四");

        //获取
        System.out.println(ops.get("1001"));

        //设置有效时间
        ops.set("1003", "王五", 60, TimeUnit.SECONDS);

        //如果不存在,再新增
        ops.setIfAbsent("1004", "赵六");
        ops.setIfAbsent("1004", "钱八");

//        //自增  自减
//        ops.set("age", 18);
//        ops.increment("age", 3);
//        ops.decrement("age", 2);

        //删除
        redisTemplate.delete("1001");
    }

}
SpringDataRedisTest.java

 

2.2.操作字符串类型数据

  //测试字符串
    @Test
    public void testString() {
        ValueOperations ops = redisTemplate.opsForValue();
        //新增数据
        ops.set("name", "张根");
        //获取数据
        String name = (String) ops.get("name");
        System.out.println(name);
        //设置有效时间6秒
        ops.set("1003", "王五", 60, TimeUnit.SECONDS);
        //如果不存在再新增
        ops.setIfAbsent("1004", "赵六");
        //自增/自减
        ops.set("age", 18);
        ops.increment("age", 6);
        ops.decrement("age", 3);
        System.out.println(ops.get("age"));
        //删除
        redisTemplate.delete("name");
    }

 

2.3.操作哈希类型数据

//测试Hash
    @Test
    public void testHash() {
        HashOperations ops = redisTemplate.opsForHash();
        //1.新增数据
        ops.put("user", "name", "张根");
        ops.put("user", "age", "18");
        ops.put("user", "sex", "Man");
        //获取 user的 name属性
        Object userName = ops.get("user", "name");
        System.out.println(userName);

        //获取所有的key
        Set keys = ops.keys("user");
        for (Object key : keys) {
            System.out.println(key);
        }
        //获取所有的values
        List values = ops.values("user");
        for (Object value : values) {
            System.out.println(value);
        }
        //删除某1属性
        ops.delete("user", "name");

        //删除整个hash
        ops.delete("user");

    }

 

2.4.操作列表类型数据

//测试list
    @Test
    public void testList() {
        ListOperations ops = redisTemplate.opsForList();
        ops.leftPush("userList", "张根");
        ops.leftPushAll("userList", "b", "C", "D");
        //获取list的长度
        System.out.println(ops.size("userList"));
        //遍历
        List userList = ops.range("userList", 0, -1);
        for (Object o : userList) {
            System.out.println(o);
        }
        //删除
        ops.rightPop("userList");
    }

 

2.5.操作无序集合类型数据

 //测试set
    @Test
    public void testSet() {
        SetOperations ops = redisTemplate.opsForSet();
        //添加
        ops.add("501", "A", "b", "c");
        //遍历查询
        Set members = ops.members("501");
        for (Object member : members) {
            System.out.println(member);
        }

        //移除集合元素
        ops.remove("501", "A", "b");

        //获取set长度
        Long size = ops.size("501");
        System.out.println(size);

        //求2个集合的交集
        ops.add("502", "A", "B", "c");
        Set intersect = ops.intersect("501", "502");
        System.out.println(intersect);
        //求2个集合的差集
        Set difference = ops.difference("501", "502");
        System.out.println(difference);


    }

 

2.6.操作有序集合类型数据

   //测试有序集合Zset
    @Test
    public void testZset() {
        ZSetOperations ops = redisTemplate.opsForZSet();
        //添加
        ops.add("5001", "Tom", 10);
        ops.add("5001", "Jack", 20);
        ops.add("5001", "Albert", 30);

        //遍历查询
        Set userSet = ops.range("5001", 0, -1);
        for (Object user : userSet) {
            System.out.println(user);
        }

        //修改有序集合中的元素的分数 +16分
        ops.incrementScore("5001", "Jack", 16);

        //删除有序集合中的元素
        ops.remove("5001", "Albert");

    }

 

2.7.通用操作

 //测试通用API
    @Test
    public void testGenericOperation() {
        //模糊查询redis数据库中所有key
        Set keys = redisTemplate.keys("*");
        for (Object key : keys) {
            System.out.println(key);
        }

        //判断key是否存在
        Boolean isExist = redisTemplate.hasKey("5001");
        System.out.println(isExist);

        //判断key的类型
        DataType type = redisTemplate.type("5001");
        System.out.println(type.name());

        //判断key剩余存活时间
        Long expire = redisTemplate.getExpire("5001");
        System.out.println(expire);

        //删除key
        redisTemplate.delete("5001");
        
    }

 

 

 

 

 

 

 

 

参考

posted on 2022-06-09 18:16  Martin8866  阅读(1294)  评论(0编辑  收藏  举报