Redis 教程

Redis 教程

Redis 概述

Redis(Remote Dictionary Server),即远程字典服务。是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。

与 memcached 一样,为了保证效率,数据都是缓存在内存中。区别的是 redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了 master-slave (主从) 同步。

Redis 能该干什么?

  1. 内存存储、持久化,内存是断电即失的,所以需要持久化(RDB、AOF)
  2. 高效率、用于高速缓冲
  3. 发布订阅系统
  4. 地图信息分析等

Redis 安装

这里介绍 Docker 的安装方式:

# 启动 redis 服务
docker run -d -p 6379:6379 --name redis redis:latest
# 查看服务是否开启
docker ps
# 停止正在运行的 redis 服务
docker stop redis
# 重启 redis 服务
docker start redis

# 访问容器
docker exec -it redis /bin/bash
# 使用容器内客户端测试连接
redis-cli

127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set name locke
OK
127.0.0.1:6379> get name
"locke"
127.0.0.1:6379> keys *    # 查看当前数据库中所有的 key
127.0.0.1:6379> flushdb   # 清空当前数据库
127.0.0.1:6379> flushall  # 清空全部数据库的内容
127.0.0.1:6379> exit      # 退出客户端

# 使用 redis 官方提供的性能测试工具
# 测试:100 个并发连接,100000 请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000

五大数据类型

Redis 是一个开源、内存存储的数据结构服务器,可用作数据库高速缓存消息队列代理。它支持多种类型的数据结构,如:字符串 (strings)、哈希表 (hashes)、列表 (lists)、集合 (sets)、有序集合 (sorted sets) 与范围查询,bitmaps,位图hyperloglogs,地理空间 (geospaial),索引半径查询等数据类型。内置复制、Lua 脚本、LRU 驱动时间、事务以及不同级别磁盘持久化功能,同时通过 Redis Sentinel 提供高可用,通过 Redis Cluster 提供自动分区

String

127.0.0.1:6379> set key1 vl  # 设置值
127.0.0.1:6379> get key1     # 获取值
127.0.0.1:6379> keys *       # 获得所有的 key
127.0.0.1:6379> exists key1  # 判断某一个 key 是否存在
127.0.0.1:6379> strlen key1  # 获取字符串的长度

127.0.0.1:6379> set user:1 {name:zhangsan,age:30}

List

Redis 列表是最简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。一个列表最多可以包含 232 - 1 个元素(4294967295,每个列表超过 40 亿个元素)。

正如图 Redis 中 List 是可以进行双端操作的,所以命令也就分为了 LXXXRLLL 两类,有时候 L 也表示 List 例如 LLEN

127.0.0.1:6379> lpush list one    # 将一个值或者多个值,插入到列表头部(左边插入)
127.0.0.1:6379> lpush list two
127.0.0.1:6379> lpush list three
127.0.0.1:6379> rpush list right  # 将一个值或者多个值,插入到列表尾部(右边插入)

127.0.0.1:6379> lpop list         # 移除list的第一个元素
127.0.0.1:6379> lpop list 2       # 移除list的前两个元素
127.0.0.1:6379> rpop list 1       # 移除list的最后一个元素

127.0.0.1:6379> lrange list 0 -1  # 获取 list 中的值
127.0.0.1:6379> lrange list 0 1   # 通过区间获取具体的值
127.0.0.1:6379> lindex list 2     # 通过下标获得 list 中的某一个值

127.0.0.1:6379> llen list         # 返回列表的长度

127.0.0.1:6379> lrem list 1 one   # 移除 list 集合中指定个数的 value,精确匹配

总结:

  1. 它实际上是一个链表,before node after ,left , right 都可以插入值
  2. 如果 key 不存在,创建新的链表
  3. 如果 key 存在,新增内容
  4. 如果移除了所有值,空链表,也代表不存在
  5. 在两边插入或者改动值,效率最高,中间元素相对来说效率会低一点

事务

Redis 事务本质:一组命令的集合。一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行。

  1. Redis 事务没有隔离级别的概念。

  2. 所有的命令在事物中,并没有直接被执行,只有发起执行命令的时候才会执行。

  3. redis 单条命令是保证原子性的,但是事务不保证原子性

127.0.0.1:6379> multi          # 开启事务
OK
127.0.0.1:6379(TX)> set k1 v1  # 命令入队
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec       # 执行事务
1) OK
2) OK
3) "v2"
4) OK

Jedis

使用 Java 来操作 Redis,Jedis 是 Redis 官方推荐使用的 Java 连接 redis 的客户端的开发工具,使用 java 操作 redis 中间件。

  1. 导入对应的依赖
<dependencies>
    <!--导入jedis的包-->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.2.0</version>
    </dependency>
    <!--fastjson 存一些数据用的-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.48</version>
    </dependency>
</dependencies>
  1. 编码测试:
    1. 连接数据库
    2. 操作命令
    3. 断开连接
package com.jihu;
import redis.clients.jedis.Jedis;
public class TestPing {
    public static void main(String[] args) {
        // 1. new jedis 对象即可
        Jedis jedis = new Jedis("192.168.56.130", 6379);
        jedis.auth("123456");

        // jedis 所有的命令就是我们之前学习的所有指令
        System.out.println(jedis.ping());

    }
}
  1. 事务的操作
package com.jihu;
import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class TestTX {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.56.130",6379);
        jedis.auth("123456");
    	jedis.flushDB();

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("hello","world");
        jsonObject.put("name","jihu");
        // 开启事务
        Transaction multi = jedis.multi();
        String result = jsonObject.toJSONString();
        jedis.watch(result)   // 给 result 加乐观锁

        try {
            multi.set("user1",result);
            multi.set("user2",result);
            int i = 1/0;      // 代码抛出异常,事务执行失败

            multi.exec();     // 执行事务
        } catch (Exception exception) {
            multi.discard();  // 放弃事务
            exception.printStackTrace();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();    // 关闭连接
        }
    }
}


SpringBoot 整合

SpringBoot 操作数据:spring-data jpa jdbc mongodb redis

说明: 在 SpringBoot 2.x 之后,原来使用的 jedis 被替换为了 lettuce:

  1. jedis : 采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用 jedis pool 连接池! 更像 BIO 模式
  2. lettuce : 采用 netty,实例可以再多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了,更像 NIO 模式

SpringBoot 整合 Redis 的具体操作如下:

  1. 构建 SpringBoot 项目,导入依赖

img

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 配置连接:application.yaml
spring:
  data:
    redis:
      ## 单机模式
      host: 127.0.0.1 # 地址
      port: 6379      # 端口
      # 通用配置
      username:             # 用户名
      password:             # 密码
      database: 0           # 指定数据库序号
      connect-timeout: 1000 # 连接超时时间(毫秒)
      timeout: 1000         # 操作超时时间(毫秒)
      client-name:          # 客户端名称(不知道干嘛用的)
      client-type: lettuce  # 驱动类型
      # 连接池配置
      lettuce:
        pool:
          min-idle: 1    # 最小空闲连接(默认0)
          max-idle: 8    # 最大空闲连接(默认8)
          max-active: 16 # 最大连接数(默认8,使用负值表示没有限制)
          max-wait: -1ms # 最大阻塞等待时间(默认-1,负数表示没限制)
  1. 测试
@SpringBootTest
class Springboot10RedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        // redisTemplate: 操作不同的数据类型,api和我们的指令是一样的
        // redisTemplate.opsForValue(): 表示操作字符串 类似String
        // redisTemplate.opsForList(): 表示操作List ,类似list
        redisTemplate.opsForList();
        redisTemplate.opsForValue().set("mykey","jihu");
        System.out.println(redisTemplate.opsForValue().get("mykey"));

        // 除了基本的操作,我们常用的方法都可以直接通过 redisTemplate 操作,比如事务和基本的 CRUD
    }
}
  1. RedisUtil 配置 (CRUD 操作 string | map | list | set)
@Service
public class RedisUtil {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 将 list 放入缓存
     *
     * @param key   键
     * @param value 值
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取 list 缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1 代表所有值
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
  1. 再测试
@SpringBootTest
class Springboot10RedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisUtil redisUtil;

    @Test
    void contextLoads() throws JsonProcessingException {

        // redisTemplate: 操作不同的数据类型,api 和我们的指令是一样的
        // redisTemplate.opsForValue(): 表示操作字符串 类似 String
        // redisTemplate.opsForList(): 表示操作 List ,类似 list
        redisTemplate.opsForValue().set("user", "locke");
        System.out.println(redisTemplate.opsForValue().get("user"));

        // 除了基本的操作,我们常用的方法都可以直接通过 redisTemplate 操作,比如事务和基本的 CRUD
    }

    // 使用 redisUtil 对 redis 操作进行封装,使用起来更加简洁
    @Test
    public void testRedis() {
        redisUtil.lSet("user", "lockegogo");
        // 获取 key 的值
        System.out.println(redisUtil.lGet("user", 0, -1));
    }
}

参考资料

  1. 狂神聊 Redis
  2. 图解 Redis
posted @   Lockegogo  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示