Redis极简教程

简介

Redis 是用C语言开发完全开源免费的,遵守BSD协议的,一个高性能的,key-value型的,NOSQL数据库。

特点

  • 可以将内存中的数据持久化到硬盘中,重启的时候可以从硬盘中再次加载
  • 拥有丰富的数据类型,String、Hash、List、Set、ZSet(SortedSet)是常用的数据类型
  • 极高的读写性能
  • 拥有高可用架构,支持集群部署

安装

  1. Github下载地址:https://github.com/tporadowski/redis/releases
  2. 中文官网下载地址:http://www.redis.cn/
  3. github上面下载下来的压缩包默认是包含了Redis服务端程序和一个客户端访问程序的,redis-server.exe为Redis的服务端,redis-cli.exe为Redis的客户端。在redis-cli中可以用redis特有的语法或者说命令来和服务端交互,实现数据的CURD等操作,实际开发过程中,则是使用具体的工具类或者框架来和redis的服务端交互,例如java使用Jedis来和Redis交互。
  4. 首先启动server,再启动cli,这时候cli端会自动连接上服务端,尝试在cli中执行一些命令,config get *(查看Redis详细配置信息的命令)

    可以看到配置信息已经在cli中打印出来了,dbfilename配置为数据库文件的名称,默认是dump.rdb,requirepass配置为数据库的访问密码,可以看到当前为空,即无需密码就可以访问

数据类型

官方文档:https://www.redis.net.cn/tutorial/3508.html

  1. String

String是Redis中最基本的数据类型
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象
string类型是Redis最基本的数据类型,一个键最大能存储512MB。
单值单Value

  • SET key1 beijing : 添加一条数据,SET为关键字,key1 是键 ,beijing 是值
  • keys * :查询所有的键 , redis关键字不区分大小写
  • GET key1 :根据键查找值
  • string 的其他命令
    • del :根据键删除
    • append :追加
    • strlen :根据键查询值的长度
    • incr :Increment,值在当前基础上加1,仅对数字有效,可用于高并发下的秒杀活动
    • decr :DeleteCreate,值在当前基础上减1,仅对数字有效
    • setex : SetWithExpire,添加一条数据,并指定多久过期
    • setnx : SetIfNotExist,添加一条数据,若指定的键已经存在就添加失败,若不存在添加成功
    • mset :MoreSet,批量添加,类似的还有mget(批量根据建获取值),msetnx(批量添加,若指定的某个键已经存在,全部添加失败,否则全部添加成功)
  1. Hash

hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。Redis 中每个 hash 可以存储 2 的 32 次方减 1 个键值对(40多亿)
KV模式不变,但V是一个键值对。有点像java中的Map

  • hset user id 11 : 添加一条记录,hset为关键字, user 为键,id 11 为值,此时的值就是一个键值对结构了
  • hget user id:根据键和【值中的键】查询一条记录
  • hmset customer id 11 name xiaoming age 20:批量添加数据,此时的键为customer,值是id 11 name xiaoming age 20,但同时整个值呈现的是KV的结构
  • hmget customer id name age:批量根据键+值中的键查询值中的值
  • hgetall customer:根据键获取值
  • hash的其他命令:
    • hlen:根据键查询值的数量
    • hexists key :在键里面的某个值得键是否存在
    • hkeys/hvals:根据键获取值中所有的键/所有的值
    • hincrby/hincrbyfloat:定量增加整数,定量增加小数
    • hsetnx:添加时候,判断是否已经存在
  1. List

Redis列表是简单的字符串列表,按照插入顺序排序。可以从头部(左边)或者尾部(右边)进行插入。一个列表最多可以包含 2 的 32 次方 - 1 个元素 (4294967295, 每个列表可容纳超过40亿个元素)。
单值多value

  • lpush list01 1 2 3 4 5:LeftPush,创建一个键为list01的列表,并有序的从左边添加 1 2 3 4 5 这几个元素
  • lrange list01 0 -1:从左边查询键为list01的列表
  • rpush list02 1 2 3 4 5:RightPush,创建一个键为list02的列表,并有序的从右边添加 1 2 3 4 5 这几个元素
  • lpop list01:从list01列表的左边弹出一个元素
  • lindex list01 3:按照下标访问列表元素
  • list的其他命令:
    • llen:求长度
    • lrem key :删除N个value
    • ltrlm key 开始index 结束index :截取指定范围的值后再赋值给key
  1. Set

Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的时间复杂度都是O(1)。集合中最大的成员数为 2 的 32 次方 - 1 (4294967295, 每个集合可存储40多亿个成员)。
单值多value

  • sadd set01 1 1 2 2 3 3:创建一个键为set01的集合,重复的值会被覆盖。
  • smembers set01:根据键查询值
  • sismember set01 3:判断set01集合中是否存在值为3的元素
  • Set的其他命令:
    • scard:获取集合里面元素的个数
    • srem key value :根据键删除值中的某个元素
    • srandmember key 3 :随机获取集合中的3个元素,可用于高并发场景下的抽奖
    • spop key :随机出栈

C#客户端

StackExchange.Redis:StackOverflow开源的一个Redis(C#)客户端
Microsoft.Extensions.Caching.Redis:微软官方基于StackExchange.Redis 封装后的Redis客户端

下面用代码演示基于Microsoft.Extensions.Caching.Redis和Redis-Server进行交互

  • 新建控制台应用程序,项目属性如下所示

  • 项目目录结构和nuget依赖

  • RedisUtil为redis交互工具类,封装了Redis常用数据类型的存储和读取操作。具体代码如下

using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RedisDemo.Utils
{
    class RedisUtil
    {

        public static readonly Lazy<RedisUtil> lazy = new Lazy<RedisUtil>(() => new RedisUtil());

        public static RedisUtil redis { get { return lazy.Value; } }

        private RedisUtil() { }

        private static IDatabase db = null;

        static RedisUtil()
        {
            ConnectionMultiplexer conn = ConnectionMultiplexer.Connect("127.0.0.1:6379");
            db = conn.GetDatabase();
        }

        /// <summary>
        /// String类型set
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool StringSet(string key, string value)
        {
            return db.StringSet(key, value);
        }

        /// <summary>
        /// String类型set
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="timeSpan">过期时间</param>
        /// <returns></returns>
        public static bool StringSet(string key, string value, TimeSpan timeSpan)
        {
            return db.StringSet(key, value, timeSpan);
        }

        /// <summary>
        /// String类型get
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string StringGet(string key)
        {
            return db.StringGet(key);
        }

        /// <summary>
        /// Hash类型set
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="key"></param>
        /// <param name="dic"></param>
        public static void HashSet<V>(string key, Dictionary<string, V> dic)
        {
            if (dic == null || dic.Count <= 0) { return; }
            HashEntry[] entries = new HashEntry[dic.Count];
            List<string> keys = new List<string>(dic.Keys);
            for (int i = 0; i < dic.Count; i++)
            {
                string value = JsonConvert.SerializeObject(dic[keys[i]]);
                entries[i] = new HashEntry(keys[i], value);
            }
            db.HashSet(key, entries);
        }

        /// <summary>
        /// Hash类型set
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool HashSet<V>(string key, string field, V value)
        {
            return db.HashSet(key, field, JsonConvert.SerializeObject(value));
        }

        /// <summary>
        /// Hash类型get
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static Dictionary<string, V> HashGet<V>(string key)
        {
            HashEntry[] entries = db.HashGetAll(key);
            if (entries != null && entries.Length > 0)
            {
                Dictionary<string, V> dics = new Dictionary<string, V>();
                foreach (var item in entries)
                {
                    dics.Add(item.Name, JsonConvert.DeserializeObject<V>(item.Value));
                }
                return dics;
            }
            return null;
        }

        /// <summary>
        /// Hash类型get
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public static string HashGet(string key, string field)
        {
            return db.HashGet(key, field);
        }

        /// <summary>
        /// List添加的时候只能一个一个的添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static bool ListSet<T>(string key, List<T> values)
        {
            if (values == null | values.Count <= 0) { return false; }
            for (int i = 0; i < values.Count; i++)
            {
                db.ListLeftPush(key, JsonConvert.SerializeObject(values[i]));
            }
            return true;
        }

        public static List<T> ListGet<T>(string key)
        {
            List<T> list = new List<T>();
            RedisValue[] values = db.ListRange(key, 0, -1);
            foreach (var item in values)
            {
                list.Add((T)JsonConvert.DeserializeObject(item));
            }
            return list;
        }

        public static bool SetSet<T>(string key, List<T> values)
        {
            if (values == null | values.Count <= 0) { return false; }
            for (int i = 0; i < values.Count; i++)
            {
                db.SetAdd(key, JsonConvert.SerializeObject(values[i]));
            }
            return true;
        }

        public static List<T> SetGet<T>(string key)
        {
            List<T> list = new List<T>();
            RedisValue[] values = db.SetMembers(key);
            foreach (var item in values)
            {
                list.Add((T)JsonConvert.DeserializeObject(item));
            }
            return list;
        }





    }
}


  • Main 方法中编写测试代码
using Newtonsoft.Json;
using RedisDemo.Models;
using RedisDemo.Utils;
using System;
using System.Collections.Generic;

namespace RedisDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            //string            
            bool isok = RedisUtil.StringSet("age", "20", new TimeSpan(1, 0, 0));
            Console.WriteLine(isok);
            string result = RedisUtil.StringGet("age");
            Console.WriteLine(result);

            //Hash
            //基本数据类型
            //Dictionary<string, string> dic01 = new Dictionary<string, string>();
            //dic01.Add("dic-key01", "dic-v1");
            //dic01.Add("dic-key02", "dic-v2");
            //RedisUtil.HashSet("dic01", dic01);
            //Dictionary<string, string> result = RedisUtil.HashGet<string>("dic01");
            //Console.WriteLine(JsonConvert.SerializeObject(result));

            //dic的value为一个实体类
            //Dictionary<string, Sku> dic02 = new Dictionary<string, Sku>();
            //dic02.Add("dic-key01", new Sku() { id = 1, name = "复印纸", price = 10.00M });
            //dic02.Add("dic-key02", new Sku() { id = 2, name = "A5复印纸", price = 100.00M });
            //RedisUtil.HashSet("dic02", dic02);
            //Dictionary<string, Sku> result = RedisUtil.HashGet<Sku>("dic02");
            //Console.WriteLine(JsonConvert.SerializeObject(result));

            //dic的value为一个嵌套实体类
            //Dictionary<string, Spu> dic03 = new Dictionary<string, Spu>();
            //dic03.Add("k1", new Spu() { id = 1, name = "复印纸", skus = new List<Sku>() { new Sku() { id = 1, name = "A3复印纸", price = 1.00M } } });
            //dic03.Add("k2", new Spu() { id = 2, name = "打印纸", skus = new List<Sku>() { new Sku() { id = 1, name = "A3打印纸", price = 91.00M } } });
            //RedisUtil.HashSet("dic03", dic03);
            //Dictionary<string, Spu> result = RedisUtil.HashGet<Spu>("dic03");
            //Console.WriteLine(JsonConvert.SerializeObject(result));

            //List
            //List<int> lists = new List<int>() { 1, 2, 3, 4, 5 };
            //bool isok = RedisUtil.ListSet("list02", lists);
            //List<long> result = RedisUtil.ListGet<long>("list02");
            //Console.WriteLine(JsonConvert.SerializeObject(result));

            //Set
            //List<int> lists = new List<int>() { 1, 2, 3, 4, 5,5 };
            //bool isok = RedisUtil.SetSet("set01", lists);
            //List<long> result = RedisUtil.SetGet<long>("set01");
            //Console.WriteLine(JsonConvert.SerializeObject(result));




        }
    }
}


  • String类型存储和读取

 bool isok = RedisUtil.StringSet("age", "20", new TimeSpan(1, 0, 0));
 Console.WriteLine(isok);
 string result = RedisUtil.StringGet("age");
 Console.WriteLine(result);

TimeSpan为设置的过期时间,三个参数分别表示时,分,秒
输出结果过为

Hello World!
True
20
  • Hash存储一个基本数据类型的字典集合
 Dictionary<string, string> dic01 = new Dictionary<string, string>();
 dic01.Add("dic-key01", "dic-v1");
 dic01.Add("dic-key02", "dic-v2");
 RedisUtil.HashSet("dic01", dic01);
 Dictionary<string, string> result = RedisUtil.HashGet<string>("dic01");
 Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
{"dic-key01":"dic-v1","dic-key02":"dic-v2"}
  • Hash存储一个value为实体类的字典
            Dictionary<string, Sku> dic02 = new Dictionary<string, Sku>();
            dic02.Add("dic-key01", new Sku() { id = 1, name = "复印纸", price = 10.00M });
            dic02.Add("dic-key02", new Sku() { id = 2, name = "A5复印纸", price = 100.00M });
            RedisUtil.HashSet("dic02", dic02);
            Dictionary<string, Sku> result = RedisUtil.HashGet<Sku>("dic02");
            Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
{"dic-key01":{"id":1,"name":"复印纸","price":10.00},"dic-key02":{"id":2,"name":"A5复印纸","price":100.00}}
  • Hash存储一个value为嵌套的实体类的字典
            Dictionary<string, Spu> dic03 = new Dictionary<string, Spu>();
            dic03.Add("k1", new Spu() { id = 1, name = "复印纸", skus = new List<Sku>() { new Sku() { id = 1, name = "A3复印纸", price = 1.00M } } });
            dic03.Add("k2", new Spu() { id = 2, name = "打印纸", skus = new List<Sku>() { new Sku() { id = 1, name = "A3打印纸", price = 91.00M } } });
            RedisUtil.HashSet("dic03", dic03);
            Dictionary<string, Spu> result = RedisUtil.HashGet<Spu>("dic03");
            Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
{"k1":{"id":1,"name":"复印纸","skus":[{"id":1,"name":"A3复印纸","price":1.00}]},"k2":{"id":2,"name":"打印纸","skus":[{"id":1,"name":"A3打印纸","price":91.00}]}}
  • List存储一个int类型的List集合,这里存的时候实际是int32,但是取出来的时候是int64,所以使用了long来存方取出的数据
            List<int> lists = new List<int>() { 1, 2, 3, 4, 5 };
            bool isok = RedisUtil.ListSet("list02", lists);
            List<long> result = RedisUtil.ListGet<long>("list02");
            Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
[5,4,3,2,1]
  • Set存储一个int集合,从输出结果可以看到,重复的那个5没有存进去,redis的set数据类型是无序不可重复的
            List<int> lists = new List<int>() { 1, 2, 3, 4, 5, 5 };
            bool isok = RedisUtil.SetSet("set01", lists);
            List<long> result = RedisUtil.SetGet<long>("set01");
            Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
[1,2,3,4,5]

spring-boot客户端

  • 关于java客户端就以spring-boot做为切入点简单演示
  • org.springframework.data.redis.core 只是封装了常用的接口,具体实现还是通过jedis或者lettuce去和redis-server交互
  • spring-boot 2.0之前默认的redis客户端是jedis;之后默认的是lettuce
  • 新建spring-boot的web应用,采用maven来管理依赖,项目文件结构如下:

  • 在pom.xml中增加如下dependency。

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

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
  • 修改application.properties。配置redis-server的访问地址
server.port=8081
spring.redis.host=127.0.0.1
spring.redis.port=6379
  • 新建一个RestController,并命名为TestRedisController
@RestController
@RequestMapping("/redis/")
public class TestRedisController {}
  • 注入RedisTemplate对象,此对象为springframework框架提供的一个对象,通过此对象实现spring-boot和redis-server的交互
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
  • 相关示例

    /**
     * String类型set
     *
     * @param key
     * @param value
     * @return
     */
    @GetMapping("string/set/{key}/{value}")
    public boolean stringSet(@PathVariable("key") String key, @PathVariable("value") String value) {
        redisTemplate.opsForValue().set(key, value);
        return true;
    }

    /**
     * String类型get
     *
     * @param key
     * @return
     */
    @GetMapping("string/get/{key}")
    public String stringGet(@PathVariable("key") String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * Hash类型ser
     *
     * @param key
     * @return
     */
    @GetMapping("hash/set/{key}")
    public boolean hashSet(@PathVariable("key") Integer key) {
        UserDto userDto = new UserDto().setId(key).setName("redis").setStature(0.55D);
        Map<String, String> map = new Hashtable<>();
        map.put(key.toString(), JSON.toJSONString(userDto));
        redisTemplate.opsForHash().putAll(key.toString(), map);
        return true;
    }

    /**
     * Hash类型ser
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    @GetMapping("hash/set/{key}/{field}/{value}")
    public boolean hashSet(@PathVariable("key") String key, @PathVariable("field") String field, @PathVariable("value") String value) {
        redisTemplate.opsForHash().put(key, field, value);
        return true;
    }

    /**
     * Hash类型get
     *
     * @param key
     * @return
     */
    @GetMapping("hash/get/{key}")
    public UserDto hashGet(@PathVariable("key") String key) {
        String result = JSON.toJSONString(redisTemplate.opsForHash().get(key, key));
        return JSON.parseObject(result, UserDto.class);
    }

    /**
     * Hash类型get
     *
     * @param key
     * @param field
     * @return
     */
    @GetMapping("hash/get/{key}/{field}")
    public String hashGet(@PathVariable("key") String key, @PathVariable("field") String field) {
        return JSON.toJSONString(redisTemplate.opsForHash().get(key, field));
    }

    /**
     * List类型set - 一个一个的增加
     *
     * @param key
     * @param value
     * @return
     */
    @GetMapping("list/set/{key}/{value}")
    public boolean listSet(@PathVariable("key") String key, @PathVariable("value") String value) {
        String[] array = value.split(",");
        for (String item : array) {
            redisTemplate.opsForList().leftPush(key, item);
        }
        return true;
    }

    /**
     * List类型get
     *
     * @param key
     * @return
     */
    @GetMapping("list/get/{key}")
    public List<String> listGet(@PathVariable("key") String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    /**
     * Set类型set
     *
     * @param key
     * @param value
     * @return
     */
    @GetMapping("set/set/{key}/{value}")
    public boolean setSet(@PathVariable("key") String key, @PathVariable("value") String value) {
        String[] array = value.split(",");
        for (String item : array) {
            redisTemplate.opsForSet().add(key, item);
        }
        return true;
    }

    /**
     * Set类型get
     *
     * @param key
     * @return
     */
    @GetMapping("set/get/{key}")
    public Set<String> setGet(@PathVariable("key") String key) {
        return redisTemplate.opsForSet().members(key);
    }

常用命令

  • del key:删除某一个key,对应的value也就删除了
  • flushdb :清空当前数据库,删除所有数据
  • keys *:查询所有key

引用

代码

posted @ 2020-06-17 16:10  Naylor  阅读(475)  评论(0编辑  收藏  举报