C#操作redis
入门步骤:
安装redis–安装可视化软件RedisDesktopManager–C#操作redis
前两步软件的安装教程很多,这里不赘述。
一、类库的选择
在C#中使用Redis,一般有两种方式:
1、ServiceStack.Redis,据说是Redis官方推荐使用的驱动类库,但是是收费的。
2、StackExchange.Redis,可能性能要比ServiceStack.Redis差点,但是是免费的。
经过多方调研,我选用StackExchange.Redis来实现Redis操作,可找到的资料也更多。
二、添加StackExchange.Redis引用
想要在C#中使用Redis,首先得要有个Redis支持的C#版的驱动。
通过网络下载或nuget安装,得到Redis相关的dll,添加到项目中引用。这里介绍下通过NuGet方式添加
第一步:在项目中右键,选择管理NuGet管理包
第二步:搜索StackExchange.Redis添加,我这里已经添加过了所以没有添加按钮
注意.net framework的版本要相适应
通过这两步,会在项目中自动添加StackExchange.Redis引用
有需要的可以自行添加Newtonsoft.Json引用
补充完整后引用如图
三、利用StackExchange.Redis对数据库进行增删查改
论坛里有不少教程,都是给出RedisHelper类,可自己调用这样的用法,如下面几篇文章
https://blog.csdn.net/u011301348/article/details/105215016
https://blog.csdn.net/wanlong360599336/article/details/46771477
https://blog.csdn.net/weixin_30892037/article/details/98005759
https://blog.csdn.net/yangwohenmai1/article/details/93536539
对我而言,更想学数据库连接,写入,增删查改的具体方法,下面的原文连接很友好。
https://blog.csdn.net/kingshown_WZ/article/details/89603057
我这里在原文程序的基础上扩展功能,对redis各种数据类型的操作做了完整补充。程序结构在上图中可以看到。
1、新建控制台程序
同上步操作添加Nuget包
2、添加UserInfoDto.cs用户实体
public class UserInfoDto
{
public int Id { get; set; }
public string StaffId { get; set; }
public string StaffName { get; set; }
public string Password { get; set; }
public System.DateTime LastLoginTime { get; set; }
}
3、添加Redis数据库辅助操作类RedisHelper.cs
注意:private static readonly ConfigurationOptions ConfigurationOptions = ConfigurationOptions.Parse(“127.0.0.1:6379,password=123456”);
设置连接数据库的IP、端口号和密码,若没有设置密码可去掉后半句。
class RedisHelper
{
private static readonly ConfigurationOptions ConfigurationOptions = ConfigurationOptions.Parse("127.0.0.1:6379,password=123456");
private static readonly object Locker = new object();
private static ConnectionMultiplexer _redisConn;
/// <summary>
/// 单例获取
/// </summary>
public static ConnectionMultiplexer RedisConn
{
get
{
if (_redisConn == null)
{
// 锁定某一代码块,让同一时间只有一个线程访问该代码块
lock (Locker)
{
if (_redisConn == null || !_redisConn.IsConnected)
{
_redisConn = ConnectionMultiplexer.Connect(ConfigurationOptions);
}
}
}
return _redisConn;
}
}
}
4、 添加Redis数据库业务实现类RedisDemo.cs
这部分程序是操作数据库的主要部分
下面有对string、Hash、List、Set、SortedSet五种类型的基本操作
备注是自己加的,也比较详细,有什么问题欢迎大家指出
class RedisDemo
{
//键值对
public static void StringTest()
{
// Using:定义了一个范围,等范围结束以后进行资源的释放,结束后调用Dispose()
using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
{
//测试0,文件夹下入数据
string key0 = "StringTest:";
//默认为db0
//括号内可填写1-15,如var db2 = conn.GetDatabase(2);
var db = conn.GetDatabase(); //在Redis中获得与数据库的交互式连接
db.StringSet(key0+"num", "138");
db.StringSet(key0 + "time", DateTime.Now.ToString());
var num = db.StringGet("StringTest:num");
Console.WriteLine(num);
//测试1,写入数据,读取数据
string key = "StringTest";
if (db.KeyExists(key))
db.KeyDelete(key);
db.StringSet(key, "1008611");
var value = db.StringGet(key);
Console.WriteLine(value);
//测试2,获取当前时间
string key2 = "StringTest2";
//如果key已经存在并且是字符串,则此命令将值附加在字符串的末尾
//如果key不存在,则会创建它并将其设置为空字符串,类似于SET
//if (db.KeyExists(key2))
// db.KeyDelete(key2);
//db.StringAppend(key2, DateTime.Now.ToString());
db.StringSet(key2, DateTime.Now.ToString());
Console.WriteLine(db.StringGet(key2));
//测试3,控制台写入
string value3 = Console.ReadLine();
Console.WriteLine("value3=" + value3);
string key3 = "StringTest3";
db.StringSet(key3, value3);
Console.WriteLine(db.StringGet(key3));
// 测试4,批量读写数据
// KeyValuePair<RedisKey, RedisValue>[] values
//以KeyValuePair数组形式批量写入
var keyvp1 = new KeyValuePair<RedisKey, RedisValue>("name1", "Jhon");
var keyvp2 = new KeyValuePair<RedisKey, RedisValue>("name2", "Lilei");
var keyvp3 = new KeyValuePair<RedisKey, RedisValue>("name3", "Jim");
KeyValuePair<RedisKey, RedisValue>[] values = { keyvp1, keyvp2, keyvp3 };
db.StringSet(values);
//批量读取key的值
RedisKey[] rkarray = { "name1", "name2", "name3" };
RedisValue[] rvarray = db.StringGet(rkarray);
foreach (var item in rvarray)
{
Console.WriteLine(item);
}
//测试5,将对象以Json格式存入string中
db.StringSet("myfirstname", "Li");
string str = db.StringGet("myfirstname");
db.StringSet("mylastname", "Shuxian", TimeSpan.FromSeconds(20));//设置时间,20s后过期。
str = db.StringGet("mylastname");
//创建对象
UserInfoDto User1 = new UserInfoDto()
{
Id = 97,
LastLoginTime = DateTime.Now,
Password ="xxxxxx",
StaffId = "xxxxxx",
StaffName = "xxx"
};
string user1_Json = JsonConvert.SerializeObject(User1);//序列化,对象转化为Json格式
db.StringSet("stringtest_Json", user1_Json);
string user1_JsonResult = db.StringGet("stringtest_Json");//读取Json格式的key
Console.WriteLine(user1_JsonResult);
User1 = JsonConvert.DeserializeObject<UserInfoDto>(user1_JsonResult);//反序列化
Console.WriteLine(User1);
}
}
//Hash类型
//string类型的域和值的映射表
//常用来存储对象信息
public static void HashTest()
{
// C# 泛型集合 List<数据类型>
List<UserInfoDto> list = new List<UserInfoDto>();
for (int i = 0; i < 11; ++i)
{
list.Add(new UserInfoDto()
{
Id = i,
LastLoginTime = DateTime.Now,
Password = "password_" + i.ToString(),
StaffId = "StaffId_" + i.ToString(),
StaffName = "StaffName_" + i.ToString()
});
}
using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
{
//测试1:对象序列化为JSON字符串写入
string key = "HashSetTest";
var db = conn.GetDatabase();
if (db.KeyExists(key))
db.KeyDelete(key);
//string listKey = IdentityMap.CreateKey<UserInfoDto>();
HashEntry[] items = new HashEntry[list.Count];
for (int i = 1; i < list.Count; i++)
{
// 将指定的对象序列化为JSON字符串。
string json = JsonConvert.SerializeObject(list[i]);
db.HashSet(key, list[i].Id, json);
Console.WriteLine(db.HashGet(key, list[i].Id));
Console.WriteLine(db.HashGet(key, "StaffId"));
db.HashDelete(key, "password");//无效
}
//测试2:将对象以plain text格式希尔
string key2 = "HashSetTest2";
//if (db.KeyExists(key2))
// db.KeyDelete(key2);
//为哈希表的每一个域设值
//bool HashSet(RedisKey key, RedisValue hashField, RedisValue value)
for (int i = 1; i < 5; i++)
{
key2 = "HashSetTest" + list[i].Id.ToString();
if (db.KeyExists(key2))
db.KeyDelete(key2);
db.HashSet(key2, "ID", list[i].Id);
db.HashSet(key2, "password", list[i].Password);
db.HashSet(key2, "StaffId", list[i].StaffId);
db.HashSet(key2, "StaffName", list[i].StaffName);
db.HashSet(key2, "LastLoginTime", DateTime.Now.ToString());
Console.WriteLine(db.HashGet(key2, list[i].Id));
//删除key中的域
db.HashDelete(key2, "password");
}
//测试3:删除key中的域
string key3 = "HashDeletTest";
db.HashSet(key3, "ID", 123456111111111111);
db.HashSet(key3, "password", "xxxxxx");
db.HashSet(key3, "StaffId", "xxxxxxxxxx");
db.HashDelete(key3, "password");
}
Console.ReadLine();
}
//列表数据类型
//列表按照插入顺序排序,可将一个元素插入列表的头部和尾部
public static void ListTest()
{
using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
{
string key = "ListTest";
var db = conn.GetDatabase();
if (db.KeyExists(key))
db.KeyDelete(key);
for (int i = 0; i < 10; i++)
{
// 将指定的值插入存储在key的列表的开头 ,相当于栈
// 如果键不存在,则在执行推入操作之前将其创建为空列表
db.ListLeftPush(key, "left_" + i.ToString());
db.ListRightPush(key, "right_" + i.ToString());
}
Console.WriteLine("写入完成");
var length = db.ListLength("list"); //读出list的长度
Console.WriteLine(length);
var str = db.ListLeftPop(key); //从顶部拿出数据
Console.WriteLine(str);
str = db.ListRightPop(key); //从底部拿出数据
Console.WriteLine(str);
//返回存储在键列表中指定的元素。
//偏移量start和stop是从零开始的索引,0是列表的第一个元素(列表的头),1是下一个元素,依此类推。
//这些偏移也可以是负数,表示从列表。用于示例,-1是列表的最后一个元素,-2是倒数第二个元素,依此类推。
//注意,如果您有一个从0到100的数字列表,LRANGE list 0 10将返回11个元素,也就是说,包含最右边的项。
var list = db.ListRange(key, 0, 4);
foreach (var item in list)
{
Console.WriteLine(item);
}
str = db.ListRemove(key, "left_2"); //删除list中的单个数值
Console.WriteLine(str);
str = db.ListInsertAfter(key, list[3], "After"); //在某一位置后插入数据
Console.WriteLine(str);
str = db.ListInsertBefore(key, list[3], "Before"); //在某一位置前插入数据
Console.WriteLine(str);
//删除list中的数据
while (db.ListLength(key) != 0)
{
//从redis数据库弹出List里的数据
//var str = db.ListRightPop(key);
//Console.WriteLine(str);
}
}
}
//Set是String类型的无序集合
public static void SetTest()
{
List<UserInfoDto> list = new List<UserInfoDto>();
DateTime dt = DateTime.Now;
for (int i = 1; i < 4; i++)
{
list.Add(new UserInfoDto()
{
Id = i,
LastLoginTime = dt,
Password = "password" + i.ToString(),
StaffId = "StaffId_" + i.ToString(),
StaffName = "StaffName_" + i.ToString()
});
}
using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
{
//测试1
string key = "SetTest:";
var db = conn.GetDatabase();
db.KeyDelete(key);
//string listKey = IdentityMap.CreateKey<UserInfoDto>();
HashEntry[] items = new HashEntry[list.Count];
for (int i = 0; i < list.Count; i++)
{
string json = JsonConvert.SerializeObject(list[i]);
db.KeyDelete(key + list[i].Id.ToString());
// 以Json格式存储
db.SetAdd(key + list[i].Id.ToString(), json);
//以string格式存储
db.SetAdd(key + list[i].Id.ToString() + ":Id", list[i].Id);
db.SetAdd(key + list[i].Id.ToString() + ":password", list[i].Password);
db.SetAdd(key + list[i].Id.ToString() + ":StaffId", list[i].StaffId);
db.SetAdd(key + list[i].Id.ToString() + ":StaffName", list[i].StaffName);
db.SetAdd(key + list[i].Id.ToString() + ":LastLoginTime", DateTime.Now.ToString());
//SSCAN命令用于对集合进行增量迭代。
//注意:要通过游标恢复迭代,请将原始的可枚举或枚举数转换为IScanningCursor。
var result = db.SetScan(key, "*password99*").FirstOrDefault();
Console.WriteLine(result);
}
Console.WriteLine("Complete test1!");
//测试2,set命令
//冒号后可在目录下创建文件夹
string key2 = "citys:";
db.KeyDelete(key2);
RedisValue[] citys1 = { "北京", "上海", "广州" };
db.SetAdd(key2 + "1", citys1);
RedisValue[] citys2 = { "成都", "重庆", "西安" };
db.SetAdd(key2 + "2", citys2);
RedisValue[] citys3 = { "太原", "大连", "徐州" };
db.SetAdd(key2 + "3", citys3);
db.SetMove("citys:2", "citys:1", "成都");
db.SetRemove("citys:3", "大连");
}
}
//有序集合
//每个集合元素都有一个对应的double类型的分数
public static void SortedSet()
{
List<UserInfoDto> list = new List<UserInfoDto>();
for (int i = 1; i < 5; i++)
{
list.Add(new UserInfoDto()
{
Id = i,
LastLoginTime = DateTime.Now,
Password = "password" + i.ToString(),
StaffId = "StaffId_" + i.ToString(),
StaffName = "StaffName_" + i.ToString()
});
}
using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
{
//测试2
var db = conn.GetDatabase();
string key = "SortedSetTest:";
db.KeyDelete("SortedSetTest");
foreach (var item in list)
{
string json = JsonConvert.SerializeObject(item);
db.KeyDelete(key + item.Id.ToString());
db.KeyDelete("SortedSetTest" + item.Id.ToString() + ":name");
db.KeyDelete("SortedSetTest" + item.Id.ToString() + ":StaffId");
//db.SetAdd(key + list[i].Id.ToString(), json);
db.SortedSetAdd(key + item.Id.ToString() + ":name", item.StaffName, item.Id);
db.SortedSetAdd(key + item.Id.ToString() + ":StaffId", item.StaffName, item.Id);
}
Console.WriteLine("写入完成");
Console.WriteLine("读取两条记录");
var result = db.SortedSetRangeByRank(key, 1, 3);
for (int i = 0; i < result.Length; i++)
{
Console.WriteLine(result[i]);
}
var result2 = db.SortedSetRangeByRankWithScores(key, 0, -1, Order.Descending);
var result3 = db.SortedSetScan(key, "*99*", 10).ToList();
for (int i = 0; i < result3.Count; i++)
{
Console.WriteLine(result3[i]);
}
Console.ReadLine();
//测试1
string key0 = "SortedSetTest0";
var db2 = conn.GetDatabase(2);
var rep = db2.SortedSetAdd(key0, "北京", 6521);
Console.WriteLine(rep);
var city1 = new SortedSetEntry("北京", 4451);
var city2 = new SortedSetEntry("上海", 3400);
var city3 = new SortedSetEntry("广州", 3459);
var city4 = new SortedSetEntry("成都", 3300);
var city5 = new SortedSetEntry("太原", 2459);
SortedSetEntry[] citys = { city1, city2, city3, city4, city5 };
var rep2 = db2.SortedSetAdd(key0, citys);
Console.WriteLine(rep2);
var res = db2.SortedSetRangeByRank(key0, 1, 3);
for (int i = 0; i < res.Length; i++)
{
Console.WriteLine(res[i]);
}
}
}
}
5、 Program.cs类
主程序,对上面各部分的功能进行测试
class Program
{
static void Main(string[] args)
{
//字符串
RedisDemo.StringTest();
//Hash
//RedisDemo.HashTest();
//List
//RedisDemo.ListTest();
//Console.ReadKey();
//Set
//RedisDemo.SetTest();
//SortedSet
//RedisDemo.SortedSet();
}
}
这部分就不一一展示测试结果了
其他功能测试
添加定时器,定时往redis数据库中写入数据,并在控制台显示
static int i = 1;
static void Main2(string[] args)
{
ConnectionMultiplexer conn = RedisHelper.RedisConn;
string key = "Data Storage";
var db = conn.GetDatabase(3);
if (db.KeyExists(key))
db.KeyDelete(key);
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 5 seconds.
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press /'q/' to quit the sample.");
while (Console.Read() == 'q')
{
Console.WriteLine("结束!");
}
void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("Hello World!");
db.ListLeftPush(key, "left_" + i.ToString());
i++;
var str = db.ListGetByIndex(key, 0); //从顶部拿出数据
Console.WriteLine(str);
}
}
控制台输出
可视化中查看数据库的写入
四、注意
1、程序运行前启动redis服务器
打开可视化工具,若redis设置了密码,要输入密码才可打开数据库。
2、选择数据写入的数据库
redis默认16个数据库,如何选择将数据写入哪个数据库呢?
var db = conn.GetDatabase(); //在Redis中获得与数据库的交互式连接
该语句连接数据库,括号为空默认写入db0
var db = conn.GetDatabase(3);即可将数据写入db3数据库
3、在数据库内添加文件夹存储
开始时将key全部写入db0中,数据存储凌乱,后来找到了添加文件夹的方法
具体操作:key值后加冒号
string key = "SetTest:";
var db = conn.GetDatabase();
db.KeyDelete(key);
//string listKey = IdentityMap.CreateKey<UserInfoDto>();
HashEntry[] items = new HashEntry[list.Count];
for (int i = 0; i < list.Count; i++)
{
string json = JsonConvert.SerializeObject(list[i]);
db.KeyDelete(key + list[i].Id.ToString());
// 以Json格式存储
db.SetAdd(key + list[i].Id.ToString(), json);
//以string格式存储
db.SetAdd(key + list[i].Id.ToString() + ":Id", list[i].Id);
db.SetAdd(key + list[i].Id.ToString() + ":password", list[i].Password);
db.SetAdd(key + list[i].Id.ToString() + ":StaffId", list[i].StaffId);
db.SetAdd(key + list[i].Id.ToString() + ":StaffName", list[i].StaffName);
db.SetAdd(key + list[i].Id.ToString() + ":LastLoginTime", DateTime.Now.ToString());
对应的文件夹添加情况如图
string key = “SetTest:”; 该key值加了冒号,成为文件夹
子文件夹也是,通过加冒号添加文件夹。
下文中也有添加文件夹的说明,大家可多方面参考学习
https://blog.csdn.net/a6864657/article/details/103863349
五、Redis高级功能
redis还有事件、消息队列、同步异步等高级功能,找了找其他参考,有以下几篇文章可参考,本人未进行试验。