//从第1个开始,依次向左插入值。如果键不存在,先创建再插入值 队列形式 先进后出,后进先出
//插入后形式 <-- 10,9,8,7,6,5,4,3,2,1 <-- 方向向左依次进行
stopwatch.Start();
for (int i = 0; i < 10; i++)
{
var getobjlist = RedisCacheHelper.Instance.ListLeftPush("leftlistkey", (i + 1).ToString());
}
stopwatch.Stop();
Console.WriteLine("在列表头部插入值消耗时间:" + stopwatch.ElapsedMilliseconds.ToString());
//从第1个开始,依次向右插入值。如果键不存在,先创建再插入值 先进先出,后进后出
//插入后形式 1,2,3,4,5,6,7,8,9,10 --> 方向向右依次进行
stopwatch.Start();
for (int i = 0; i < 10; i++)
{
var getobjlist = RedisCacheHelper.Instance.ListRightPush("rightlistkey", (i + 1).ToString());
}
stopwatch.Stop();
Console.WriteLine("在列表尾部插入值消耗时间:" + stopwatch.ElapsedMilliseconds.ToString());

//获取Left列表中的队列元素 从列表头部开始读取
var getleftvalue = RedisCacheHelper.Instance.ListRange("leftlistkey");
Console.WriteLine(string.Join(",", getleftvalue));
//获取Right列表中的队列元素 从列表头部开始读取
var getrightvalue = RedisCacheHelper.Instance.ListRange("rightlistkey");
Console.WriteLine(string.Join(",", getrightvalue));
//从左边第一个元素开始 循环移除并返回该移除的值
Console.WriteLine("从左边开始");
while (true)
{
var getleftvalue = RedisCacheHelper.Instance.ListLeftPop("leftlistkey");
if (!string.IsNullOrEmpty(getleftvalue))
{
Console.WriteLine("移除:" + getleftvalue);
}
else
{
break;
}
}
//从右边第一个元素开始 循环移除并返回该移除的值
Console.WriteLine("从右边开始");
while (true)
{
var getrightvalue = RedisCacheHelper.Instance.ListRightPop("rightlistkey");
if (!string.IsNullOrEmpty(getrightvalue))
{
Console.WriteLine("移除:" + getrightvalue);
}
else
{
break;
}
}
//从左边第一个元素开始 循环移除并返回该移除的值 替换一下Key后
Console.WriteLine("从左边开始");
while (true)
{
var getleftvalue = RedisCacheHelper.Instance.ListLeftPop("rightlistkey");
if (!string.IsNullOrEmpty(getleftvalue))
{
Console.WriteLine("移除:" + getleftvalue);
}
else
{
break;
}
}
//从右边第一个元素开始 循环移除并返回该移除的值 替换一下Key后
Console.WriteLine("从右边开始");
while (true)
{
var getrightvalue = RedisCacheHelper.Instance.ListRightPop("leftlistkey");
if (!string.IsNullOrEmpty(getrightvalue))
{
Console.WriteLine("移除:" + getrightvalue);
}
else
{
break;
}
}
//列表长度 不存在则返回0
var getlength = RedisCacheHelper.Instance.ListLength("leftlistkey");
Console.WriteLine("列表长度:" + getlength);
//删除List中的元素 并返回删除的个数 不存在则返回0
var getlong = RedisCacheHelper.Instance.ListDelRange("leftlistkey", "6");
Console.WriteLine("删除List中的元素,并返回删除的个数:" + getlong);
//清空列表
RedisCacheHelper.Instance.ListClear("leftlistkey");
使用List类型 模拟用户并发抢购商品
//模拟数据 想List类型表中加入一定数量的库存 50个商品
for (int i = 1; i <= 50; i++)
{
var getvalue = RedisCacheHelper.Instance.ListRightPush("orderlist", i.ToString());
//Console.WriteLine("返回结果:" + getvalue);
}
//模拟创建多个用户 100个用户
List<TestRedis> testlist = new List<TestRedis>();
for (int i = 0; i < 100; i++)
{
testlist.Add(new TestRedis() { Uid = (i + 1) });
}
//先清空
RedisCacheHelper.Instance.ListClear("orderSuccessList");
//使用List类型模拟并发情况 不用担心库存为负的情况
//模拟多个用户抢购限时商品 100个用户抢50个商品
stopwatch.Start();
List<Task> taskList = new List<Task>();
foreach (var item in testlist)
{
var task = Task.Run(() =>
{
try
{
//先自减,获取自减后的值
long order_Num = -1;
long.TryParse(RedisCacheHelper.Instance.ListRightPop("orderlist"), out order_Num);
if (order_Num > 0)
{
//下面执行订单逻辑(这里不考虑业务出错的情况)
RedisCacheHelper.Instance.ListLeftPush("orderSuccessList", item.Uid.ToString()); //记录下单成功的用户
//操作数据库相关逻辑 可以使用“消息队列”或“服务”进行数据库同步操作
Console.WriteLine("用户:" + item.Uid + ",抢到了商品:" + order_Num);
}
else
{
Console.WriteLine("商品已经被抢光了,用户" + item.Uid + "未抢到");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
});
taskList.Add(task);
}
Task.WaitAll(taskList.ToArray());
stopwatch.Stop();
Console.WriteLine("模拟并发场景消耗时间:" + stopwatch.ElapsedMilliseconds.ToString());
应用场景:
Redis list 的应用场景非常多,也是 Redis 最重要的数据结构之一,比如 twitter 的关注列表,粉丝列表等都可以用 Redis 的 list 结构来实现,比较好理解,这里不再重复。
实现方式:
Redis list 的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis 内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。
最后附上Helper
/// <summary>
/// 在列表头部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public long ListLeftPush(string redisKey, string redisValue, int db = -1)
{
var _db = GetDatabase(db);
return _db.ListLeftPush(redisKey, redisValue);
}
/// <summary>
/// 在列表尾部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public long ListRightPush(string redisKey, string redisValue, int db = -1)
{
var _db = GetDatabase(db);
return _db.ListRightPush(redisKey, redisValue);
}
/// <summary>
/// 在列表尾部插入数组集合。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public long ListRightPush(string redisKey, IEnumerable<string> redisValue, int db = -1)
{
var _db = GetDatabase(db);
var redislist = new List<RedisValue>();
foreach (var item in redisValue)
{
redislist.Add(item);
}
return _db.ListRightPush(redisKey, redislist.ToArray());
}
/// <summary>
/// 移除并返回存储在该键列表的第一个元素 反序列化
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public T ListLeftPop<T>(string redisKey, int db = -1) where T : class
{
var _db = GetDatabase(db);
return JsonConvert.DeserializeObject<T>(_db.ListLeftPop(redisKey));
}
/// <summary>
/// 移除并返回存储在该键列表的最后一个元素 反序列化
/// 只能是对象集合
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public T ListRightPop<T>(string redisKey, int db = -1) where T : class
{
var _db = GetDatabase(db);
return JsonConvert.DeserializeObject<T>(_db.ListRightPop(redisKey));
}
/// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="redisKey"></param>
/// <param name="db"></param>
/// <returns></returns>
public string ListLeftPop(string redisKey, int db = -1)
{
var _db = GetDatabase(db);
return _db.ListLeftPop(redisKey);
}
/// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="redisKey"></param>
/// <param name="db"></param>
/// <returns></returns>
public string ListRightPop(string redisKey, int db = -1)
{
var _db = GetDatabase(db);
return _db.ListRightPop(redisKey);
}
/// <summary>
/// 列表长度
/// </summary>
/// <param name="redisKey"></param>
/// <param name="db"></param>
/// <returns></returns>
public long ListLength(string redisKey, int db = -1)
{
var _db = GetDatabase(db);
return _db.ListLength(redisKey);
}
/// <summary>
/// 返回在该列表上键所对应的元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public IEnumerable<string> ListRange(string redisKey, int db = -1)
{
var _db = GetDatabase(db);
var result = _db.ListRange(redisKey);
return result.Select(o => o.ToString());
}
/// <summary>
/// 根据索引获取指定位置数据
/// </summary>
/// <param name="redisKey"></param>
/// <param name="start"></param>
/// <param name="stop"></param>
/// <param name="db"></param>
/// <returns></returns>
public IEnumerable<string> ListRange(string redisKey, int start, int stop, int db = -1)
{
var _db = GetDatabase(db);
var result = _db.ListRange(redisKey, start, stop);
return result.Select(o => o.ToString());
}
/// <summary>
/// 删除List中的元素 并返回删除的个数
/// </summary>
/// <param name="redisKey">key</param>
/// <param name="redisValue">元素</param>
/// <param name="type">大于零 : 从表头开始向表尾搜索,小于零 : 从表尾开始向表头搜索,等于零:移除表中所有与 VALUE 相等的值</param>
/// <param name="db"></param>
/// <returns></returns>
public long ListDelRange(string redisKey, string redisValue, long type = 0, int db = -1)
{
var _db = GetDatabase(db);
return _db.ListRemove(redisKey, redisValue, type);
}
/// <summary>
/// 清空List
/// </summary>
/// <param name="redisKey"></param>
/// <param name="db"></param>
public void ListClear(string redisKey, int db = -1)
{
var _db = GetDatabase(db);
_db.ListTrim(redisKey, 1, 0);
}
View Code
作者:PeterZhang
出处:https://www.cnblogs.com/peterzhang123
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。