• 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 :清空当前数据库,删除所有数据

    引用

    代码

  • 相关阅读:
    Java 设计模式-享元模式(Flyweight)
    Java 设计模式-状态模式模式(State)
    Java 设计模式-建造者模式(Builder)
    Java 设计模式-抽象工厂(Abstract Factory)
    Spring 之 JMS 基于JMS的RPC
    Spring 之 JMS 监听JMS消息
    Spring 之 JMS 发送和接收消息
    数据结构
    BFS vs DFS
    子集和排列
  • 原文地址:https://www.cnblogs.com/Naylor/p/13152994.html
Copyright © 2020-2023  润新知