服务器之家:专注于服务器技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Redis - Redis中的String类型及使用Redis解决订单秒杀超卖问题

Redis中的String类型及使用Redis解决订单秒杀超卖问题

2020-12-28 15:42谢友海 Redis

这篇文章主要介绍了Redis中的String类型及使用Redis解决订单秒杀超卖问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

本系列将和大家分享Redis分布式缓存,本章主要简单介绍下Redis中的String类型,以及如何使用Redis解决订单秒杀超卖问题。

Redis中5种数据结构之String类型:key-value的缓存,支持过期,value不超过512M。

Redis中的String类型及使用Redis解决订单秒杀超卖问题

Redis是单线程的,比如SetAll & AppendToValue & GetValues & GetAndSetValue & IncrementValue & IncrementValueBy等等,这些看上去像是组合命令,但实际上是一个具体的命令,是一个原子性的命令,不可能出现中间状态,可以应对一些并发情况。下面我们直接通过代码来看下具体使用。

首先来看下Demo的项目结构:

Redis中的String类型及使用Redis解决订单秒杀超卖问题

此处推荐使用的是ServiceStack包,虽然它是收费的,有1小时3600次请求限制,但是它是开源的,可以将它的源码下载下来破解后使用,网上应该有挺多相关资料,有兴趣的可以去了解一波。

一、Redis中与String类型相关的API

首先先来看下Redis客户端的初始化工作:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System;
 
namespace TianYa.Redis.Init
{
 /// <summary>
 /// redis配置文件信息
 /// 也可以放到配置文件去
 /// </summary>
 public sealed class RedisConfigInfo
 {
  /// <summary>
  /// 可写的Redis链接地址
  /// format:ip1,ip2
  ///
  /// 默认6379端口
  /// </summary>
  public string WriteServerList = "127.0.0.1:6379";
 
  /// <summary>
  /// 可读的Redis链接地址
  /// format:ip1,ip2
  ///
  /// 默认6379端口
  /// </summary>
  public string ReadServerList = "127.0.0.1:6379";
 
  /// <summary>
  /// 最大写链接数
  /// </summary>
  public int MaxWritePoolSize = 60;
 
  /// <summary>
  /// 最大读链接数
  /// </summary>
  public int MaxReadPoolSize = 60;
 
  /// <summary>
  /// 本地缓存到期时间,单位:秒
  /// </summary>
  public int LocalCacheTime = 180;
 
  /// <summary>
  /// 自动重启
  /// </summary>
  public bool AutoStart = true;
 
  /// <summary>
  /// 是否记录日志,该设置仅用于排查redis运行时出现的问题,
  /// 如redis工作正常,请关闭该项
  /// </summary>
  public bool RecordeLog = false;
 }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using ServiceStack.Redis;
 
namespace TianYa.Redis.Init
{
 /// <summary>
 /// Redis管理中心
 /// </summary>
 public class RedisManager
 {
  /// <summary>
  /// Redis配置文件信息
  /// </summary>
  private static RedisConfigInfo _redisConfigInfo = new RedisConfigInfo();
 
  /// <summary>
  /// Redis客户端池化管理
  /// </summary>
  private static PooledRedisClientManager _prcManager;
 
  /// <summary>
  /// 静态构造方法,初始化链接池管理对象
  /// </summary>
  static RedisManager()
  {
   CreateManager();
  }
 
  /// <summary>
  /// 创建链接池管理对象
  /// </summary>
  private static void CreateManager()
  {
   string[] writeServerConStr = _redisConfigInfo.WriteServerList.Split(',');
   string[] readServerConStr = _redisConfigInfo.ReadServerList.Split(',');
   _prcManager = new PooledRedisClientManager(readServerConStr, writeServerConStr,
    new RedisClientManagerConfig
    {
     MaxWritePoolSize = _redisConfigInfo.MaxWritePoolSize,
     MaxReadPoolSize = _redisConfigInfo.MaxReadPoolSize,
     AutoStart = _redisConfigInfo.AutoStart,
    });
  }
 
  /// <summary>
  /// 客户端缓存操作对象
  /// </summary>
  public static IRedisClient GetClient()
  {
   return _prcManager.GetClient();
  }
 }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using System;
using TianYa.Redis.Init;
using ServiceStack.Redis;
 
namespace TianYa.Redis.Service
{
 /// <summary>
 /// redis操作的基类
 /// </summary>
 public abstract class RedisBase : IDisposable
 {
  /// <summary>
  /// Redis客户端
  /// </summary>
  protected IRedisClient _redisClient { get; private set; }
 
  /// <summary>
  /// 构造函数
  /// </summary>
  public RedisBase()
  {
   this._redisClient = RedisManager.GetClient();
  }
 
  private bool _disposed = false;
  protected virtual void Dispose(bool disposing)
  {
   if (!this._disposed)
   {
    if (disposing)
    {
     _redisClient.Dispose();
     _redisClient = null;
    }
   }
 
   this._disposed = true;
  }
 
  public void Dispose()
  {
   Dispose(true);
   GC.SuppressFinalize(this);
  }
 
  /// <summary>
  /// Redis事务处理示例
  /// </summary>
  public void Transcation()
  {
   using (IRedisTransaction irt = this._redisClient.CreateTransaction())
   {
    try
    {
     irt.QueueCommand(r => r.Set("key", 20));
     irt.QueueCommand(r => r.Increment("key", 1));
     irt.Commit(); //事务提交
    }
    catch (Exception ex)
    {
     irt.Rollback(); //事务回滚
     throw ex;
    }
   }
  }
 
  /// <summary>
  /// 清除全部数据 请小心
  /// </summary>
  public virtual void FlushAll()
  {
   _redisClient.FlushAll();
  }
 
  /// <summary>
  /// 保存数据DB文件到硬盘
  /// </summary>
  public void Save()
  {
   _redisClient.Save(); //阻塞式Save
  }
 
  /// <summary>
  /// 异步保存数据DB文件到硬盘
  /// </summary>
  public void SaveAsync()
  {
   _redisClient.SaveAsync(); //异步Save
  }
 }
}

下面直接给大家Show一波Redis中与String类型相关的API:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
using System;
using System.Collections.Generic;
 
namespace TianYa.Redis.Service
{
 /// <summary>
 /// key-value 键值对 value可以是序列化的数据 (字符串)
 /// </summary>
 public class RedisStringService : RedisBase
 {
  #region 赋值
 
  /// <summary>
  /// 设置永久缓存
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <param name="value">存储的值</param>
  /// <returns></returns>
  public bool Set(string key, string value)
  {
   return base._redisClient.Set(key, value);
  }
 
  /// <summary>
  /// 设置永久缓存
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <param name="value">存储的值</param>
  /// <returns></returns>
  public bool Set<T>(string key, T value)
  {
   return base._redisClient.Set<T>(key, value);
  }
 
  /// <summary>
  /// 带有过期时间的缓存
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <param name="value">存储的值</param>
  /// <param name="expireTime">过期时间</param>
  /// <returns></returns>
  public bool Set(string key, string value, DateTime expireTime)
  {
   return base._redisClient.Set(key, value, expireTime);
  }
 
  /// <summary>
  /// 带有过期时间的缓存
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <param name="value">存储的值</param>
  /// <param name="expireTime">过期时间</param>
  /// <returns></returns>
  public bool Set<T>(string key, T value, DateTime expireTime)
  {
   return base._redisClient.Set<T>(key, value, expireTime);
  }
 
  /// <summary>
  /// 带有过期时间的缓存
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <param name="value">存储的值</param>
  /// <param name="expireTime">过期时间</param>
  /// <returns></returns>
  public bool Set<T>(string key, T value, TimeSpan expireTime)
  {
   return base._redisClient.Set<T>(key, value, expireTime);
  }
 
  /// <summary>
  /// 设置多个key/value
  /// </summary>
  public void SetAll(Dictionary<string, string> dic)
  {
   base._redisClient.SetAll(dic);
  }
 
  #endregion 赋值
 
  #region 追加
 
  /// <summary>
  /// 在原有key的value值之后追加value,没有就新增一项
  /// </summary>
  public long AppendToValue(string key, string value)
  {
   return base._redisClient.AppendToValue(key, value);
  }
 
  #endregion 追加
 
  #region 获取值
 
  /// <summary>
  /// 读取缓存
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <returns></returns>
  public string Get(string key)
  {
   return base._redisClient.GetValue(key);
  }
 
  /// <summary>
  /// 读取缓存
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <returns></returns>
  public T Get<T>(string key)
  {
   return
    _redisClient.ContainsKey(key)
    ? _redisClient.Get<T>(key)
    : default;
  }
 
  /// <summary>
  /// 获取多个key的value值
  /// </summary>
  /// <param name="keys">存储的键集合</param>
  /// <returns></returns>
  public List<string> Get(List<string> keys)
  {
   return base._redisClient.GetValues(keys);
  }
 
  /// <summary>
  /// 获取多个key的value值
  /// </summary>
  /// <param name="keys">存储的键集合</param>
  /// <returns></returns>
  public List<T> Get<T>(List<string> keys)
  {
   return base._redisClient.GetValues<T>(keys);
  }
 
  #endregion 获取值
 
  #region 获取旧值赋上新值
 
  /// <summary>
  /// 获取旧值赋上新值
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <param name="value">存储的值</param>
  /// <returns></returns>
  public string GetAndSetValue(string key, string value)
  {
   return base._redisClient.GetAndSetValue(key, value);
  }
 
  #endregion 获取旧值赋上新值
 
  #region 移除缓存
 
  /// <summary>
  /// 移除缓存
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <returns></returns>
  public bool Remove(string key)
  {
   return _redisClient.Remove(key);
  }
 
  /// <summary>
  /// 移除多个缓存
  /// </summary>
  /// <param name="keys">存储的键集合</param>
  public void RemoveAll(List<string> keys)
  {
   _redisClient.RemoveAll(keys);
  }
 
  #endregion 移除缓存
 
  #region 辅助方法
 
  /// <summary>
  /// 是否存在缓存
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <returns></returns>
  public bool ContainsKey(string key)
  {
   return _redisClient.ContainsKey(key);
  }
 
  /// <summary>
  /// 获取值的长度
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <returns></returns>
  public long GetStringCount(string key)
  {
   return base._redisClient.GetStringCount(key);
  }
 
  /// <summary>
  /// 自增1,返回自增后的值
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <returns></returns>
  public long IncrementValue(string key)
  {
   return base._redisClient.IncrementValue(key);
  }
 
  /// <summary>
  /// 自增count,返回自增后的值
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <param name="count">自增量</param>
  /// <returns></returns>
  public long IncrementValueBy(string key, int count)
  {
   return base._redisClient.IncrementValueBy(key, count);
  }
 
  /// <summary>
  /// 自减1,返回自减后的值
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <returns></returns>
  public long DecrementValue(string key)
  {
   return base._redisClient.DecrementValue(key);
  }
 
  /// <summary>
  /// 自减count,返回自减后的值
  /// </summary>
  /// <param name="key">存储的键</param>
  /// <param name="count">自减量</param>
  /// <returns></returns>
  public long DecrementValueBy(string key, int count)
  {
   return base._redisClient.DecrementValueBy(key, count);
  }
 
  #endregion 辅助方法
 }
}

测试如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System;
 
namespace MyRedis
{
 /// <summary>
 /// 学生类
 /// </summary>
 public class Student
 {
  public int Id { get; set; }
  public string Name { get; set; }
  public string Remark { get; set; }
  public string Description { get; set; }
 }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System;
using System.Collections.Generic;
using TianYa.Redis.Service;
using Newtonsoft.Json;
 
namespace MyRedis
{
 /// <summary>
 /// ServiceStack API封装测试 五大结构理解 (1小时3600次请求限制--可破解)
 /// </summary>
 public class ServiceStackTest
 {
  /// <summary>
  /// String
  /// key-value的缓存,支持过期,value不超过512M
  /// Redis是单线程的,比如SetAll & AppendToValue & GetValues & GetAndSetValue & IncrementValue & IncrementValueBy,
  /// 这些看上去是组合命令,但实际上是一个具体的命令,是一个原子性的命令,不可能出现中间状态,可以应对一些并发情况
  /// </summary>
  public static void ShowString()
  {
   var student1 = new Student()
   {
    Id = 10000,
    Name = "TianYa"
   };
 
   using (RedisStringService service = new RedisStringService())
   {
    service.Set("student1", student1);
    var stu = service.Get<Student>("student1");
    Console.WriteLine(JsonConvert.SerializeObject(stu));
 
    service.Set<int>("Age", 28);
    Console.WriteLine(service.IncrementValue("Age"));
    Console.WriteLine(service.IncrementValueBy("Age", 3));
    Console.WriteLine(service.DecrementValue("Age"));
    Console.WriteLine(service.DecrementValueBy("Age", 3));
   }
  }
 }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
 
namespace MyRedis
{
 /// <summary>
 /// Redis:Remote Dictionary Server 远程字典服务器
 /// 基于内存管理(数据存在内存),实现了5种数据结构(分别应对各种具体需求),单线程模型的应用程序(单进程单线程),对外提供插入--查询--固化--集群功能。
 /// 正是因为基于内存管理所以速度快,可以用来提升性能。但是不能当数据库,不能作为数据的最终依据。
 /// 单线程多进程的模式来提供集群服务。
 /// 单线程最大的好处就是原子性操作,就是要么都成功,要么都失败,不会出现中间状态。Redis每个命令都是原子性(因为单线程),不用考虑并发,不会出现中间状态。(线程安全)
 /// Redis就是为开发而生,会为各种开发需求提供对应的解决方案。
 /// Redis只是为了提升性能,不做数据标准。任何的数据固化都是由数据库完成的,Redis不能代替数据库。
 /// Redis实现的5种数据结构:String、Hashtable、Set、ZSet和List。
 /// </summary>
 class Program
 {
  static void Main(string[] args)
  {
   ServiceStackTest.ShowString();
   Console.ReadKey();
  }
 }
}

运行结果如下:

Redis中的String类型及使用Redis解决订单秒杀超卖问题

Redis中的String类型及使用Redis解决订单秒杀超卖问题

Redis中的String类型在项目中使用是最多的,想必大家都有所了解,此处就不再做过多的描述了。

二、使用Redis解决订单秒杀超卖问题

首先先来看下什么是订单秒杀超卖问题:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/// <summary>
/// 模拟订单秒杀超卖问题
///  超卖:订单数超过商品
///  如果使用传统的锁来解决超卖问题合适吗?
///   不合适,因为这个等于是单线程了,其他都要阻塞,会出现各种超时。
///   -1的时候除了操作库存,还得增加订单,等支付等等。
///   10个商品秒杀,一次只能进一个? 违背了业务。
/// </summary>
public class OverSellFailedTest
{
 private static bool _isGoOn = true; //秒杀活动是否结束
 private static int _stock = 0; //商品库存
 public static void Show()
 {
  _stock = 10;
  for (int i = 0; i < 5000; i++)
  {
   int k = i;
   Task.Run(() => //每个线程就是一个用户请求
   {
    if (_isGoOn)
    {
     long index = _stock;
     Thread.Sleep(100); //模拟去数据库查询库存
     if (index >= 1)
     {
      _stock = _stock - 1; //更新库存
      Console.WriteLine($"{k.ToString("0000")}秒杀成功,秒杀商品索引为{index}");
      //可以分队列,去操作数据库
     }
     else
     {
      if (_isGoOn)
      {
       _isGoOn = false;
      }
 
      Console.WriteLine($"{k.ToString("0000")}秒杀失败,秒杀商品索引为{index}");
     }
    }
    else
    {
     Console.WriteLine($"{k.ToString("0000")}秒杀停止......");
    }
   });
  }
 }
}

运行OverSellFailedTest.Show(),结果如下所示:

Redis中的String类型及使用Redis解决订单秒杀超卖问题

从运行结果可以看出不仅一个商品卖给了多个人,而且还出现了订单数超过商品数,这就是典型的秒杀超卖问题。

下面我们来看下如何使用Redis解决订单秒杀超卖问题:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/// <summary>
/// 使用Redis解决订单秒杀超卖问题
///  超卖:订单数超过商品
///  1、Redis原子性操作--保证一个数值只出现一次--防止一个商品卖给多个人
///  2、用上了Redis,一方面保证绝对不会超卖,另一方面没有效率影响,还有撤单的时候增加库存,可以继续秒杀,
///  限制秒杀的库存是放在redis,不是数据库,不会造成数据的不一致性
///  3、Redis能够拦截无效的请求,如果没有这一层,所有的请求压力都到数据库
///  4、缓存击穿/穿透---缓存down掉,请求全部到数据库
///  5、缓存预热功能---缓存重启,数据丢失,多了一个初始化缓存数据动作(写代码去把数据读出来放入缓存)
/// </summary>
public class OverSellTest
{
 private static bool _isGoOn = true; //秒杀活动是否结束
 public static void Show()
 {
  using (RedisStringService service = new RedisStringService())
  {
   service.Set<int>("Stock", 10); //库存
  }
 
  for (int i = 0; i < 5000; i++)
  {
   int k = i;
   Task.Run(() => //每个线程就是一个用户请求
   {
    using (RedisStringService service = new RedisStringService())
    {
     if (_isGoOn)
     {
      long index = service.DecrementValue("Stock"); //减1并且返回
      if (index >= 0)
      {
       Console.WriteLine($"{k.ToString("0000")}秒杀成功,秒杀商品索引为{index}");
       //service.IncrementValue("Stock"); //加1,如果取消了订单则添加库存继续秒杀
       //可以分队列,去操作数据库
      }
      else
      {
       if (_isGoOn)
       {
        _isGoOn = false;
       }
 
       Console.WriteLine($"{k.ToString("0000")}秒杀失败,秒杀商品索引为{index}");
      }
     }
     else
     {
      Console.WriteLine($"{k.ToString("0000")}秒杀停止......");
     }
    }
   });
  }
 }
}

运行OverSellTest.Show(),结果如下所示:

Redis中的String类型及使用Redis解决订单秒杀超卖问题

从运行结果可以看出使用Redis能够很好的解决订单秒杀超卖问题。

至此本文就全部介绍完了,如果觉得对您有所启发请记得点个赞哦!!!

Demo源码:

链接: https://pan.baidu.com/s/1vukiDxOLQYZX4Qd94izMpQ 提取码: bdfm

此文由博主精心撰写转载请保留此原文链接:https://www.cnblogs.com/xyh9039/p/13979522.html

版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

到此这篇关于Redis中的String类型及使用Redis解决订单秒杀超卖问题的文章就介绍到这了,更多相关Redis解决订单秒杀超卖内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/xyh9039/archive/2020/11/16/13979522.html

延伸 · 阅读

精彩推荐
  • Redisredis缓存存储Session原理机制

    redis缓存存储Session原理机制

    这篇文章主要为大家介绍了redis缓存存储Session原理机制详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    程序媛张小妍9252021-11-25
  • RedisRedis Template实现分布式锁的实例代码

    Redis Template实现分布式锁的实例代码

    这篇文章主要介绍了Redis Template实现分布式锁,需要的朋友可以参考下 ...

    晴天小哥哥2592019-11-18
  • RedisRedis集群的5种使用方式,各自优缺点分析

    Redis集群的5种使用方式,各自优缺点分析

    Redis 多副本,采用主从(replication)部署结构,相较于单副本而言最大的特点就是主从实例间数据实时同步,并且提供数据持久化和备份策略。...

    优知学院4082021-08-10
  • Redis如何使用Redis锁处理并发问题详解

    如何使用Redis锁处理并发问题详解

    这篇文章主要给大家介绍了关于如何使用Redis锁处理并发问题的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Redis具有一定的参考学习...

    haofly4522019-11-26
  • RedisRedis 6.X Cluster 集群搭建

    Redis 6.X Cluster 集群搭建

    码哥带大家完成在 CentOS 7 中安装 Redis 6.x 教程。在学习 Redis Cluster 集群之前,我们需要先搭建一套集群环境。机器有限,实现目标是一台机器上搭建 6 个节...

    码哥字节15752021-04-07
  • Redis《面试八股文》之 Redis十六卷

    《面试八股文》之 Redis十六卷

    redis 作为我们最常用的内存数据库,很多地方你都能够发现它的身影,比如说登录信息的存储,分布式锁的使用,其经常被我们当做缓存去使用。...

    moon聊技术8182021-07-26
  • Redis详解三分钟快速搭建分布式高可用的Redis集群

    详解三分钟快速搭建分布式高可用的Redis集群

    这篇文章主要介绍了详解三分钟快速搭建分布式高可用的Redis集群,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    万猫学社4502021-07-25
  • Redis关于Redis数据库入门详细介绍

    关于Redis数据库入门详细介绍

    大家好,本篇文章主要讲的是关于Redis数据库入门详细介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览...

    沃尔码6982022-01-24