C#操作redis(StackExchange.Redis)
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还有事件、消息队列、同步异步等高级功能,找了找其他参考,有以下几篇文章可参考,本人未进行试验。
https://blog.csdn.net/WuLex/article/details/78394693
————————————————
版权声明:本文为CSDN博主「Ancolie」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Ancolie/article/details/109254358
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步