反射实现Model修改前后的内容对比 【API调用】腾讯云短信 Windows操作系统下Redis服务安装图文详解 Redis入门学习
反射实现Model修改前后的内容对比
在开发过程中,我们会遇到这样一个问题,编辑了一个对象之后,我们想要把这个对象修改了哪些内容保存下来,以便将来查看和追责。
首先我们要创建一个User类
1 public class User 2 { 3 private string name; 4 public string Name 5 { 6 get { return name; } 7 set { name = value; } 8 } 9 private string age; 10 public string Age 11 { 12 get { return age; } 13 set { age = value; } 14 } 15 private string sex; 16 public string Sex 17 { 18 get { return sex; } 19 set { sex = value; } 20 } 21 }
然后在Main函数中声明并初始化一个User对象
1 User userA = new User() 2 { 3 Name = "李四", 4 Age = "25", 5 Sex = "男", 6 };
因为要对比对象编辑前后的内容,所以需要备份一下这个UserA,我们来个深拷贝
1 User userB = DeepCopyByXml<User>(userA);
1 /// <summary> 2 /// 深拷贝 3 /// </summary> 4 /// <typeparam name="T"></typeparam> 5 /// <param name="obj"></param> 6 /// <returns></returns> 7 public static T DeepCopyByXml<T>(T obj) where T : class 8 { 9 object retval; 10 using (MemoryStream ms = new MemoryStream()) 11 { 12 XmlSerializer xml = new XmlSerializer(typeof(T)); 13 xml.Serialize(ms, obj); 14 ms.Seek(0, SeekOrigin.Begin); 15 retval = xml.Deserialize(ms); 16 ms.Close(); 17 } 18 return (T)retval; 19 }
接下来的工作是修改UserA的属性,然后和UserB对比,利用反射来实现该功能
/// <summary> /// Model对比 /// </summary> /// <typeparam Name="T"></typeparam> /// <param Name="oldModel"></param> /// <param Name="newModel"></param> private static void CompareModel<T>(T oldModel, T newModel) where T : class { string changeStr = string.Empty; PropertyInfo[] properties = oldModel.GetType().GetProperties(); Console.WriteLine("--------用户信息修改汇总--------"); foreach (System.Reflection.PropertyInfo item in properties) {string name = item.Name; object oldValue = item.GetValue(oldModel); object newValue = item.GetValue(newModel); if (!oldValue.Equals(newValue)) { Console.WriteLine(name + " :由[" + oldValue + "] 改为 [" + newValue + "]"); } } }
从运行结果来看我们已经获取到了修改的内容,美中不足的是“Name”和“Age”,如何以中文显示属性名,接下来将利用C#的特性来实现
新建一个自定义的特性类TableAttribute
/* 参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。 参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。 参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。 */ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] public class TableAttribute : System.Attribute { private string fieldName; private string tableName; /// <summary> /// 表名 /// </summary> public string TableName { get { return tableName; } set { tableName = value; } } /// <summary> /// 字段名 /// </summary> public string FieldName { get { return fieldName; } set { fieldName = value; } } }
接着修改User类,加上自定义的特性TableAttribute
/// <summary> /// 用户信息实体类 /// </summary> [TableAttribute(TableName = "用户信息")] public class User { private string name; [TableAttribute(FieldName = "姓名")] public string Name { get { return name; } set { name = value; } } private string age; [TableAttribute(FieldName = "年龄")] public string Age { get { return age; } set { age = value; } } private string sex; [TableAttribute(FieldName = "性别")] public string Sex { get { return sex; } set { sex = value; } } }
最后修改一下CompareModel这个方法
1 /// <summary> 2 /// Model对比 3 /// </summary> 4 /// <typeparam Name="T"></typeparam> 5 /// <param Name="oldModel"></param> 6 /// <param Name="newModel"></param> 7 private static void CompareModel<T>(T oldModel, T newModel) where T : class 8 { 9 string changeStr = string.Empty; 10 PropertyInfo[] properties = oldModel.GetType().GetProperties(); 11 Console.WriteLine("--------用户信息修改汇总--------"); 12 foreach (System.Reflection.PropertyInfo item in properties) 13 { 14 TableAttribute tableAttribute = item.GetCustomAttribute<TableAttribute>(); 15 string name = item.Name; 16 if (tableAttribute != null) 17 name = tableAttribute.FieldName; 18 object oldValue = item.GetValue(oldModel); 19 object newValue = item.GetValue(newModel); 20 if (!oldValue.Equals(newValue)) 21 { 22 Console.WriteLine(name + " :由[" + oldValue + "] 改为 [" + newValue + "]"); 23 } 24 } 25 }
我们看一下运行结果
完整demo下载:https://files.cnblogs.com/files/LikeHeart/ExampleReflection.zip
(完)
【API调用】腾讯云短信
在之前介绍的火车票查询工具中,利用邮件和短信将查询结果推送给用户。免费短信的条数只有5条,用完之后只能单独使用邮件提醒。
最近发现腾讯云的福利,简单的介绍一下用法。
腾讯云-》产品-》通信服务-》短信-》开通服务-》添加应用-》创建签名和模板-》等待审核通过-》按照Demo测试
在整个流程中,最耗时的就是创建签名和模板,对个人来说只能选择app、公众号或小程序的方式进行申请,多亏之前折腾过一点小程序,从而闯关成功。
接下来查看官方Demo https://github.com/qcloudsms/qcloudsms/tree/master/demo/csharp
整理后的测试Demo
调用代码:
1 using QcloudSms; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ConsoleTest 9 { 10 class SmsSDKDemo 11 { 12 /// <summary> 13 /// appId 14 /// </summary> 15 private static int appId = 140xxxxx; 16 /// <summary> 17 /// appKey 18 /// </summary> 19 private static string appKey = "xxxxxxxxxxxxxxx"; 20 /// <summary> 21 /// 接收手机号 22 /// </summary> 23 private static string phoneNumber = "xxxxxxxx"; 24 /// <summary> 25 /// 短信模板ID 26 /// </summary> 27 private static int tmplateId = xxxxxxx; 28 29 static void Main(string[] args) 30 { 31 try 32 { 33 SmsSingleSenderResult singleResult; 34 SmsSingleSender singleSender = new SmsSingleSender(appId, appKey); 35 36 singleResult = singleSender.Send(SmsType.普通短信, phoneNumber, ""); 37 Console.WriteLine(singleResult); 38 39 List<string> templParams = new List<string>(); 40 templParams.Add("G2619"); 41 templParams.Add("二等座:23 无座:128"); 42 singleResult = singleSender.SendWithParam(phoneNumber, tmplateId, templParams); 43 Console.WriteLine(singleResult); 44 } 45 catch (Exception e) 46 { 47 Console.WriteLine(e); 48 } 49 Console.Read(); 50 } 51 } 52 }
1 namespace QcloudSms 2 { 3 #region 短信类型枚举 4 /// <summary> 5 /// 短信类型枚举 6 /// </summary> 7 public enum SmsType 8 { 9 普通短信 = 0, 10 营销短信 = 1 11 } 12 #endregion 13 14 #region 单发 15 /// <summary> 16 /// 单发 17 /// </summary> 18 class SmsSingleSender 19 { 20 #region 变量 21 /// <summary> 22 /// appId 23 /// </summary> 24 private int appId; 25 /// <summary> 26 /// appkey 27 /// </summary> 28 private string appkey; 29 /// <summary> 30 /// url 31 /// </summary> 32 private string url = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms"; 33 /// <summary> 34 /// util 35 /// </summary> 36 private SmsSenderUtil util = new SmsSenderUtil(); 37 #endregion 38 39 #region 构造 40 /// <summary> 41 /// 构造函数 42 /// </summary> 43 /// <param name="sdkappid"></param> 44 /// <param name="appkey"></param> 45 public SmsSingleSender(int sdkappid, string appkey) 46 { 47 this.appId = sdkappid; 48 this.appkey = appkey; 49 } 50 #endregion 51 52 #region 普通单发短信接口 53 /// <summary> 54 /// 普通单发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名 55 /// </summary> 56 /// <param name="type">短信类型,0 为普通短信,1 营销短信</param> 57 /// <param name="phoneNumber">不带国家码的手机号</param> 58 /// <param name="msg">信息内容,必须与申请的模板格式一致,否则将返回错误</param> 59 /// <param name="extend">短信码号扩展号,格式为纯数字串,其他格式无效。默认没有开通</param> 60 /// <param name="ext">服务端原样返回的参数,可填空</param> 61 /// <returns>SmsSingleSenderResult</returns> 62 public SmsSingleSenderResult Send(SmsType type, string phoneNumber, string msg, string extend = "", string ext = "") 63 { 64 long random = util.GetRandom(); 65 long curTime = util.GetCurTime(); 66 67 // 按照协议组织 post 请求包体 68 JObject tel = new JObject(); 69 tel.Add("nationcode", SmsSenderUtil.nationCode); 70 tel.Add("mobile", phoneNumber); 71 JObject data = new JObject(); 72 data.Add("tel", tel); 73 data.Add("msg", msg); 74 data.Add("type", (int)type); 75 data.Add("sig", util.StrToHash(string.Format("appkey={0}&random={1}&time={2}&mobile={3}", appkey, random, curTime, phoneNumber))); 76 data.Add("time", curTime); 77 data.Add("extend", extend); 78 data.Add("ext", ext); 79 80 string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random; 81 HttpWebRequest request = util.GetPostHttpConn(wholeUrl); 82 byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)); 83 request.ContentLength = requestData.Length; 84 Stream requestStream = request.GetRequestStream(); 85 requestStream.Write(requestData, 0, requestData.Length); 86 requestStream.Close(); 87 88 // 接收返回包 89 HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 90 Stream responseStream = response.GetResponseStream(); 91 StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")); 92 string responseStr = streamReader.ReadToEnd(); 93 streamReader.Close(); 94 responseStream.Close(); 95 SmsSingleSenderResult result; 96 if (HttpStatusCode.OK == response.StatusCode) 97 { 98 result = util.ResponseStrToSingleSenderResult(responseStr); 99 } 100 else 101 { 102 result = new SmsSingleSenderResult(); 103 result.result = -1; 104 result.errmsg = "http error " + response.StatusCode + " " + responseStr; 105 } 106 return result; 107 } 108 #endregion 109 110 #region 指定模板单发 111 /// <summary> 112 /// 指定模板单发 113 /// </summary> 114 /// <param name="phoneNumber">不带国家码的手机号</param> 115 /// <param name="templId">模板 id</param> 116 /// <param name="templParams">模板参数列表,如模板 {1}...{2}...{3},那么需要带三个参数</param> 117 /// <param name="sign">短信签名,如果使用默认签名,该字段可缺省</param> 118 /// <param name="extend">扩展码,可填空</param> 119 /// <param name="ext">服务端原样返回的参数,可填空</param> 120 /// <returns>SmsSingleSenderResult</returns> 121 public SmsSingleSenderResult SendWithParam(string phoneNumber, int templId, List<string> templParams, string sign = "", string extend = "", string ext = "") 122 { 123 long random = util.GetRandom(); 124 long curTime = util.GetCurTime(); 125 126 // 按照协议组织 post 请求包体 127 JObject tel = new JObject(); 128 tel.Add("nationcode", SmsSenderUtil.nationCode); 129 tel.Add("mobile", phoneNumber); 130 JObject data = new JObject(); 131 data.Add("tel", tel); 132 data.Add("sig", util.CalculateSigForTempl(appkey, random, curTime, phoneNumber)); 133 data.Add("tpl_id", templId); 134 data.Add("params", util.SmsParamsToJSONArray(templParams)); 135 data.Add("sign", sign); 136 data.Add("time", curTime); 137 data.Add("extend", extend); 138 data.Add("ext", ext); 139 140 string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random; 141 HttpWebRequest request = util.GetPostHttpConn(wholeUrl); 142 byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)); 143 request.ContentLength = requestData.Length; 144 Stream requestStream = request.GetRequestStream(); 145 requestStream.Write(requestData, 0, requestData.Length); 146 requestStream.Close(); 147 148 // 接收返回包 149 HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 150 Stream responseStream = response.GetResponseStream(); 151 StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")); 152 string responseStr = streamReader.ReadToEnd(); 153 streamReader.Close(); 154 responseStream.Close(); 155 SmsSingleSenderResult result; 156 if (HttpStatusCode.OK == response.StatusCode) 157 { 158 result = util.ResponseStrToSingleSenderResult(responseStr); 159 } 160 else 161 { 162 result = new SmsSingleSenderResult(); 163 result.result = -1; 164 result.errmsg = "http error " + response.StatusCode + " " + responseStr; 165 } 166 return result; 167 } 168 #endregion 169 } 170 #endregion 171 172 #region 单发结果 173 /// <summary> 174 /// 单发结果 175 /// </summary> 176 class SmsSingleSenderResult 177 { 178 /// <summary> 179 /// 错误码,0 表示成功(计费依据),非 0 表示失败 180 /// </summary> 181 public int result { set; get; } 182 /// <summary> 183 /// 错误消息,result 非 0 时的具体错误信息 184 /// </summary> 185 public string errmsg { set; get; } 186 /// <summary> 187 /// 用户的 session 内容,腾讯 server 回包中会原样返回 188 /// </summary> 189 public string ext { set; get; } 190 /// <summary> 191 /// 本次发送标识 id,标识一次短信下发记录 192 /// </summary> 193 public string sid { set; get; } 194 /// <summary> 195 /// 短信计费的条数 196 /// </summary> 197 public int fee { set; get; } 198 /// <summary> 199 /// ToString() 200 /// </summary> 201 /// <returns></returns> 202 public override string ToString() 203 { 204 return string.Format("SmsSingleSenderResult\nresult {0}\nerrMsg {1}\next {2}\nsid {3}\nfee {4}", result, errmsg, ext, sid, fee); 205 } 206 } 207 #endregion 208 209 #region 群发 210 /// <summary> 211 /// 群发 212 /// </summary> 213 class SmsMultiSender 214 { 215 #region 变量 216 /// <summary> 217 /// appId 218 /// </summary> 219 private int appId; 220 /// <summary> 221 /// appkey 222 /// </summary> 223 private string appkey; 224 /// <summary> 225 /// url 226 /// </summary> 227 private string url = "https://yun.tim.qq.com/v5/tlssmssvr/sendmultisms2"; 228 /// <summary> 229 /// util 230 /// </summary> 231 private SmsSenderUtil util = new SmsSenderUtil(); 232 #endregion 233 234 #region 构造 235 /// <summary> 236 /// 构造 237 /// </summary> 238 /// <param name="sdkappid"></param> 239 /// <param name="appkey"></param> 240 public SmsMultiSender(int sdkappid, string appkey) 241 { 242 this.appId = sdkappid; 243 this.appkey = appkey; 244 } 245 #endregion 246 247 #region 普通群发短信接口 248 /// <summary> 249 /// 普通群发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名 250 ///【注意】 海外短信无群发功能 251 /// </summary> 252 /// <param name="type">短信类型,0 为普通短信,1 营销短信</param> 253 /// <param name="nationCode"></param> 254 /// <param name="phoneNumbers">不带国家码的手机号列表</param> 255 /// <param name="msg">信息内容,必须与申请的模板格式一致,否则将返回错误</param> 256 /// <param name="extend">扩展码,可填空</param> 257 /// <param name="ext">服务端原样返回的参数,可填空</param> 258 /// <returns>SmsMultiSenderResult</returns> 259 public SmsMultiSenderResult Send(SmsType type, List<string> phoneNumbers, string msg, string extend = "", string ext = "") 260 { 261 long random = util.GetRandom(); 262 long curTime = util.GetCurTime(); 263 264 // 按照协议组织 post 请求包体 265 JObject data = new JObject(); 266 data.Add("tel", util.PhoneNumbersToJSONArray(SmsSenderUtil.nationCode, phoneNumbers)); 267 data.Add("type", (int)type); 268 data.Add("msg", msg); 269 data.Add("sig", util.CalculateSig(appkey, random, curTime, phoneNumbers)); 270 data.Add("time", curTime); 271 data.Add("extend", extend); 272 data.Add("ext", ext); 273 274 string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random; 275 HttpWebRequest request = util.GetPostHttpConn(wholeUrl); 276 byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)); 277 request.ContentLength = requestData.Length; 278 Stream requestStream = request.GetRequestStream(); 279 requestStream.Write(requestData, 0, requestData.Length); 280 requestStream.Close(); 281 282 // 接收返回包 283 HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 284 Stream responseStream = response.GetResponseStream(); 285 StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")); 286 string responseStr = streamReader.ReadToEnd(); 287 streamReader.Close(); 288 responseStream.Close(); 289 SmsMultiSenderResult result; 290 if (HttpStatusCode.OK == response.StatusCode) 291 { 292 result = util.ResponseStrToMultiSenderResult(responseStr); 293 } 294 else 295 { 296 result = new SmsMultiSenderResult(); 297 result.result = -1; 298 result.errmsg = "http error " + response.StatusCode + " " + responseStr; 299 } 300 return result; 301 } 302 #endregion 303 304 #region 指定模板群发 305 /// <summary> 306 /// 指定模板群发 307 /// 【注意】海外短信无群发功能 308 /// </summary> 309 /// <param name="phoneNumbers">不带国家码的手机号列表</param> 310 /// <param name="templId"> 模板 id</param> 311 /// <param name="templParams">模板参数列表</param> 312 /// <param name="sign"> 签名,如果填空,系统会使用默认签名</param> 313 /// <param name="extend">扩展码,可以填空</param> 314 /// <param name="ext">服务端原样返回的参数,可以填空</param> 315 /// <returns> SmsMultiSenderResult</returns> 316 public SmsMultiSenderResult SendWithParam(List<string> phoneNumbers, int templId, List<string> templParams, string sign = "", string extend = "", string ext = "") 317 { 318 long random = util.GetRandom(); 319 long curTime = util.GetCurTime(); 320 321 // 按照协议组织 post 请求包体 322 JObject data = new JObject(); 323 data.Add("tel", util.PhoneNumbersToJSONArray(SmsSenderUtil.nationCode, phoneNumbers)); 324 data.Add("sig", util.CalculateSigForTempl(appkey, random, curTime, phoneNumbers)); 325 data.Add("tpl_id", templId); 326 data.Add("params", util.SmsParamsToJSONArray(templParams)); 327 data.Add("sign", sign); 328 data.Add("time", curTime); 329 data.Add("extend", extend); 330 data.Add("ext", ext); 331 332 string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random; 333 HttpWebRequest request = util.GetPostHttpConn(wholeUrl); 334 byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)); 335 request.ContentLength = requestData.Length; 336 Stream requestStream = request.GetRequestStream(); 337 requestStream.Write(requestData, 0, requestData.Length); 338 requestStream.Close(); 339 340 // 接收返回包 341 HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 342 Stream responseStream = response.GetResponseStream(); 343 StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")); 344 string responseStr = streamReader.ReadToEnd(); 345 streamReader.Close(); 346 responseStream.Close(); 347 SmsMultiSenderResult result; 348 if (HttpStatusCode.OK == response.StatusCode) 349 { 350 result = util.ResponseStrToMultiSenderResult(responseStr); 351 } 352 else 353 { 354 result = new SmsMultiSenderResult(); 355 result.result = -1; 356 result.errmsg = "http error " + response.StatusCode + " " + responseStr; 357 } 358 return result; 359 } 360 #endregion 361 } 362 #endregion 363 364 #region 群发结果 365 /// <summary> 366 /// 群发结果 367 /// </summary> 368 class SmsMultiSenderResult 369 { 370 public class Detail 371 { 372 /// <summary> 373 /// 错误码,0 表示成功(计费依据),非 0 表示失败 374 /// </summary> 375 public int result { get; set; } 376 /// <summary> 377 /// 错误消息,result 非 0 时的具体错误信息 378 /// </summary> 379 public string errmsg { get; set; } 380 /// <summary> 381 /// 手机号码 382 /// </summary> 383 public string mobile { get; set; } 384 /// <summary> 385 /// 国家码 386 /// </summary> 387 public string nationcode { get; set; } 388 /// <summary> 389 /// 本次发送标识 id,标识一次短信下发记录 390 /// </summary> 391 public string sid { get; set; } 392 /// <summary> 393 /// 短信计费的条数 394 /// </summary> 395 public int fee { get; set; } 396 /// <summary> 397 /// ToString() 398 /// </summary> 399 /// <returns></returns> 400 public override string ToString() 401 { 402 return string.Format( 403 "\tDetail result {0} errmsg {1} mobile {2} nationcode {3} sid {4} fee {5}", 404 result, errmsg, mobile, nationcode, sid, fee); 405 } 406 } 407 408 public int result; 409 public string errmsg = ""; 410 public string ext = ""; 411 public IList<Detail> detail; 412 413 public override string ToString() 414 { 415 if (null != detail) 416 { 417 return String.Format( 418 "SmsMultiSenderResult\nresult {0}\nerrmsg {1}\next {2}\ndetail:\n{3}", 419 result, errmsg, ext, String.Join("\n", detail)); 420 } 421 else 422 { 423 return String.Format( 424 "SmsMultiSenderResult\nresult {0}\nerrmsg {1}\next {2}\n", 425 result, errmsg, ext); 426 } 427 } 428 } 429 #endregion 430 431 #region 公共类 432 /// <summary> 433 /// 公共类 434 /// </summary> 435 class SmsSenderUtil 436 { 437 /// <summary> 438 /// 国家码 439 /// </summary> 440 public static string nationCode = "86"; 441 /// <summary> 442 /// 随机数生成器 443 /// </summary> 444 private Random random = new Random(); 445 446 #region GetPostHttpConn 447 /// <summary> 448 /// GetPostHttpConn 449 /// </summary> 450 /// <param name="url"></param> 451 /// <returns></returns> 452 public HttpWebRequest GetPostHttpConn(string url) 453 { 454 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 455 request.Method = "POST"; 456 request.ContentType = "application/x-www-form-urlencoded"; 457 return request; 458 } 459 #endregion 460 461 #region 生成随机数 462 /// <summary> 463 /// 生成随机数 464 /// </summary> 465 /// <returns></returns> 466 public long GetRandom() 467 { 468 return random.Next(999999) % 900000 + 100000; 469 } 470 #endregion 471 472 #region 获取请求发起时间 473 /// <summary> 474 /// 获取请求发起时间, 475 /// unix 时间戳(单位:秒),如果和系统时间相差超过 10 分钟则会返回失败 476 /// </summary> 477 /// <returns></returns> 478 public long GetCurTime() 479 { 480 Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; 481 return unixTimestamp; 482 } 483 #endregion 484 485 #region 字符串转SHA256 486 /// <summary> 487 /// 字符串转SHA256 488 /// </summary> 489 /// <param name="str"></param> 490 /// <returns></returns> 491 public string StrToHash(string str) 492 { 493 SHA256 sha256 = SHA256Managed.Create(); 494 byte[] resultByteArray = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(str)); 495 return ByteArrayToHex(resultByteArray); 496 } 497 498 /// <summary> 499 /// 将二进制的数值转换为 16 进制字符串,如 "abc" => "616263" 500 /// </summary> 501 /// <param name="byteArray"></param> 502 /// <returns></returns> 503 private static string ByteArrayToHex(byte[] byteArray) 504 { 505 string returnStr = ""; 506 if (byteArray != null) 507 { 508 for (int i = 0; i < byteArray.Length; i++) 509 { 510 returnStr += byteArray[i].ToString("x2"); 511 } 512 } 513 return returnStr; 514 } 515 #endregion 516 517 #region 将单发回包解析成结果对象 518 /// <summary> 519 /// 将单发回包解析成结果对象 520 /// </summary> 521 /// <param name="str"></param> 522 /// <returns></returns> 523 public SmsSingleSenderResult ResponseStrToSingleSenderResult(string str) 524 { 525 SmsSingleSenderResult result = JsonConvert.DeserializeObject<SmsSingleSenderResult>(str); 526 return result; 527 } 528 #endregion 529 530 #region 将群发回包解析成结果对象 531 /// <summary> 532 /// 将群发回包解析成结果对象 533 /// </summary> 534 /// <param name="str"></param> 535 /// <returns></returns> 536 public SmsMultiSenderResult ResponseStrToMultiSenderResult(string str) 537 { 538 SmsMultiSenderResult result = JsonConvert.DeserializeObject<SmsMultiSenderResult>(str); 539 return result; 540 } 541 #endregion 542 543 #region List<string>转JArray 544 /// <summary> 545 /// List<string>转JArray 546 /// </summary> 547 /// <param name="templParams"></param> 548 /// <returns></returns> 549 public JArray SmsParamsToJSONArray(List<string> templParams) 550 { 551 JArray smsParams = new JArray(); 552 foreach (string templParamsElement in templParams) 553 { 554 smsParams.Add(templParamsElement); 555 } 556 return smsParams; 557 } 558 #endregion 559 560 #region PhoneNumbersToJSONArray 561 /// <summary> 562 /// PhoneNumbersToJSONArray 563 /// </summary> 564 /// <param name="nationCode"></param> 565 /// <param name="phoneNumbers"></param> 566 /// <returns></returns> 567 public JArray PhoneNumbersToJSONArray(string nationCode, List<string> phoneNumbers) 568 { 569 JArray tel = new JArray(); 570 int i = 0; 571 do 572 { 573 JObject telElement = new JObject(); 574 telElement.Add("nationcode", nationCode); 575 telElement.Add("mobile", phoneNumbers.ElementAt(i)); 576 tel.Add(telElement); 577 } while (++i < phoneNumbers.Count); 578 return tel; 579 } 580 #endregion 581 582 #region 计算App凭证 583 /* 584 "sig" 字段根据公式 sha256(appkey=$appkey&random=$random&time=$time&mobile=$mobile)生成 585 */ 586 public string CalculateSigForTempl(string appkey, long random, long curTime, List<string> phoneNumbers) 587 { 588 string phoneNumbersString = phoneNumbers.ElementAt(0); 589 for (int i = 1; i < phoneNumbers.Count; i++) 590 { 591 phoneNumbersString += "," + phoneNumbers.ElementAt(i); 592 } 593 return StrToHash(String.Format( 594 "appkey={0}&random={1}&time={2}&mobile={3}", 595 appkey, random, curTime, phoneNumbersString)); 596 } 597 598 public string CalculateSigForTempl(string appkey, long random, long curTime, string phoneNumber) 599 { 600 List<string> phoneNumbers = new List<string>(); 601 phoneNumbers.Add(phoneNumber); 602 return CalculateSigForTempl(appkey, random, curTime, phoneNumbers); 603 } 604 605 public string CalculateSig(string appkey, long random, long curTime, List<string> phoneNumbers) 606 { 607 string phoneNumbersString = phoneNumbers.ElementAt(0); 608 for (int i = 1; i < phoneNumbers.Count; i++) 609 { 610 phoneNumbersString += "," + phoneNumbers.ElementAt(i); 611 } 612 return StrToHash(String.Format( 613 "appkey={0}&random={1}&time={2}&mobile={3}", 614 appkey, random, curTime, phoneNumbersString)); 615 } 616 #endregion 617 } 618 #endregion 619 }
demo下载路径为:https://files.cnblogs.com/files/LikeHeart/ConsoleTest.zip
Windows操作系统下Redis服务安装图文详解
Redis下载地址:https://github.com/MSOpenTech/redis/releases
下载msi格式的安装文件。
1.运行安装程序,单击next按钮。
2.勾选接受许可协议中的条款,单击next按钮。
3.选择安装目录,勾选添加到环境变量,单击next按钮。
4.端口号以及防火墙添加例外,单击next按钮。
5.是否设置最大内存限制,默认不勾选,单击next按钮。
6.开始安装,单击Insatll按钮。
7.等待安装,耗时不超过一分钟。
8.安装完成,单击Finsh按钮。
9.安装目录文件如下所示。
10.可以从服务中查看到redis服务已经正常运行。
Redis入门学习
一、软件安装
Redis下载地址:https://github.com/MSOpenTech/redis/releases
因为官方并不支持windows系统,需要从微软的GitHub上下载。
解压缩后文件夹内容如图所示(版本3.2.100):
最开始会用到的文件有redis-server.exe、redis-cli.exe以及一个配置文件redis.windows.conf。
1)启动redis服务,运行cmd.exe
进入到redis文件夹
cd desttop/redis
启动redis-server.exe 并使用配置文件,出现如下图所示就是启动成功了。
redis-server.exe redis.windows.conf
2)启动客户端,再打开一个cmd.exe
进入到文件夹后启动redis-cli.exe
redis-cli.exe
国际惯例,ping helloworld ,解锁熟练掌握redis的成就。
3)为什么默认使用6379端口
Redis作者antirez同学在twitter上说将在下一篇博文(http://oldblog.antirez.com/post/redis-as-LRU-cache.html)中向大家解释为什么他选择6379作为默认端口号。而现在这篇博文出炉,在解释了Redis的LRU机制之后,如期向大家解释了采用6379作为默认端口的原因。6379在是手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字。
二、基本用法
redis是以kev-value形式进行数据存储的,value有字符串、哈希表、列表、集合、有序集合等。
一些命令的使用,可以参考http://doc.redisfans.com/学习。
配置文件的使用,redis.windows-service.conf(以windows服务运行时修改),
1.密码修改# requirepass foobared //去掉注释#,将foobared替换为你自己的密码2.文件命名修改dbfilename dump.rdb // xxxx.rdb
三、C#使用Redis
1)使用到的第三方dll:
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" /> <package id="StackExchange.Redis" version="1.2.6" targetFramework="net45" />
2)搜集到的RedisHelper方法,增加了批量操作
1 /// <summary> 2 /// Redis操作 3 /// </summary> 4 public class RedisHelper 5 { 6 /// <summary> 7 /// 连接redis库的Number 8 /// </summary> 9 private int DbNum { set; get; } 10 private readonly ConnectionMultiplexer _conn; 11 /// <summary> 12 /// 自定义键前缀 13 /// </summary> 14 public string CustomKey; 15 16 #region 构造函数 17 18 public RedisHelper(int dbNum = 0) 19 : this(dbNum, null) 20 { 21 } 22 23 public RedisHelper(int dbNum, string readWriteHosts) 24 { 25 DbNum = dbNum; 26 _conn = 27 string.IsNullOrWhiteSpace(readWriteHosts) ? 28 RedisConnectionHelp.Instance : 29 RedisConnectionHelp.GetConnectionMultiplexer(readWriteHosts); 30 } 31 32 #endregion 构造函数 33 34 #region String 35 36 #region 同步方法 37 38 /// <summary> 39 /// 保存单个key value 40 /// </summary> 41 /// <param name="key">Redis Key</param> 42 /// <param name="value">保存的值</param> 43 /// <param name="expiry">过期时间</param> 44 /// <returns></returns> 45 public bool StringSet(string key, string value, TimeSpan? expiry = default(TimeSpan?)) 46 { 47 key = AddSysCustomKey(key); 48 return Do(db => db.StringSet(key, value, expiry)); 49 } 50 51 /// <summary> 52 /// 保存多个key value 53 /// </summary> 54 /// <param name="keyValues">键值对</param> 55 /// <returns></returns> 56 public bool StringSet(List<KeyValuePair<RedisKey, RedisValue>> keyValues) 57 { 58 List<KeyValuePair<RedisKey, RedisValue>> newkeyValues = 59 keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToList(); 60 return Do(db => db.StringSet(newkeyValues.ToArray())); 61 } 62 63 /// <summary> 64 /// 保存一个对象 65 /// </summary> 66 /// <typeparam name="T"></typeparam> 67 /// <param name="key"></param> 68 /// <param name="obj"></param> 69 /// <param name="expiry"></param> 70 /// <returns></returns> 71 public bool StringSet<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?)) 72 { 73 key = AddSysCustomKey(key); 74 string json = ConvertJson(obj); 75 return Do(db => db.StringSet(key, json, expiry)); 76 } 77 78 /// <summary> 79 /// 获取单个key的值 80 /// </summary> 81 /// <param name="key">Redis Key</param> 82 /// <returns></returns> 83 public byte[] StringGet(string key) 84 { 85 key = AddSysCustomKey(key); 86 return Do(db => db.StringGet(key)); 87 } 88 89 /// <summary> 90 /// 获取多个Key 91 /// </summary> 92 /// <param name="listKey">Redis Key集合</param> 93 /// <returns></returns> 94 public RedisValue[] StringGet(List<string> listKey) 95 { 96 List<string> newKeys = listKey.Select(AddSysCustomKey).ToList(); 97 return Do(db => db.StringGet(ConvertRedisKeys(newKeys))); 98 } 99 100 /// <summary> 101 /// 获取一个key的对象 102 /// </summary> 103 /// <typeparam name="T"></typeparam> 104 /// <param name="key"></param> 105 /// <returns></returns> 106 public T StringGet<T>(string key) 107 { 108 key = AddSysCustomKey(key); 109 return Do(db => ConvertObj<T>(db.StringGet(key))); 110 } 111 112 public object StringGetObj(string key) 113 { 114 key = AddSysCustomKey(key); 115 var database = _conn.GetDatabase(DbNum); 116 return database.StringGet(key); 117 } 118 119 public static object GetObjFromBytes(byte[] buffer) 120 { 121 using (System.IO.MemoryStream stream = new System.IO.MemoryStream(buffer)) 122 { 123 stream.Position = 0; 124 System.Runtime.Serialization.IFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 125 Object reobj = bf.Deserialize(stream); 126 return reobj; 127 } 128 } 129 130 /// <summary> 131 /// 为数字增长val 132 /// </summary> 133 /// <param name="key"></param> 134 /// <param name="val">可以为负</param> 135 /// <returns>增长后的值</returns> 136 public double StringIncrement(string key, double val = 1) 137 { 138 key = AddSysCustomKey(key); 139 return Do(db => db.StringIncrement(key, val)); 140 } 141 142 /// <summary> 143 /// 为数字减少val 144 /// </summary> 145 /// <param name="key"></param> 146 /// <param name="val">可以为负</param> 147 /// <returns>减少后的值</returns> 148 public double StringDecrement(string key, double val = 1) 149 { 150 key = AddSysCustomKey(key); 151 return Do(db => db.StringDecrement(key, val)); 152 } 153 154 #endregion 同步方法 155 156 #region 异步方法 157 158 /// <summary> 159 /// 保存单个key value 160 /// </summary> 161 /// <param name="key">Redis Key</param> 162 /// <param name="value">保存的值</param> 163 /// <param name="expiry">过期时间</param> 164 /// <returns></returns> 165 public async Task<bool> StringSetAsync(string key, string value, TimeSpan? expiry = default(TimeSpan?)) 166 { 167 key = AddSysCustomKey(key); 168 return await Do(db => db.StringSetAsync(key, value, expiry)); 169 } 170 171 /// <summary> 172 /// 保存多个key value 173 /// </summary> 174 /// <param name="keyValues">键值对</param> 175 /// <returns></returns> 176 public async Task<bool> StringSetAsync(List<KeyValuePair<RedisKey, RedisValue>> keyValues) 177 { 178 List<KeyValuePair<RedisKey, RedisValue>> newkeyValues = 179 keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToList(); 180 return await Do(db => db.StringSetAsync(newkeyValues.ToArray())); 181 } 182 183 /// <summary> 184 /// 保存一个对象 185 /// </summary> 186 /// <typeparam name="T"></typeparam> 187 /// <param name="key"></param> 188 /// <param name="obj"></param> 189 /// <param name="expiry"></param> 190 /// <returns></returns> 191 public async Task<bool> StringSetAsync<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?)) 192 { 193 key = AddSysCustomKey(key); 194 string json = ConvertJson(obj); 195 return await Do(db => db.StringSetAsync(key, json, expiry)); 196 } 197 198 /// <summary> 199 /// 获取单个key的值 200 /// </summary> 201 /// <param name="key">Redis Key</param> 202 /// <returns></returns> 203 public async Task<string> StringGetAsync(string key) 204 { 205 key = AddSysCustomKey(key); 206 return await Do(db => db.StringGetAsync(key)); 207 } 208 209 /// <summary> 210 /// 获取多个Key 211 /// </summary> 212 /// <param name="listKey">Redis Key集合</param> 213 /// <returns></returns> 214 public async Task<RedisValue[]> StringGetAsync(List<string> listKey) 215 { 216 List<string> newKeys = listKey.Select(AddSysCustomKey).ToList(); 217 return await Do(db => db.StringGetAsync(ConvertRedisKeys(newKeys))); 218 } 219 220 /// <summary> 221 /// 获取一个key的对象 222 /// </summary> 223 /// <typeparam name="T"></typeparam> 224 /// <param name="key"></param> 225 /// <returns></returns> 226 public async Task<T> StringGetAsync<T>(string key) 227 { 228 key = AddSysCustomKey(key); 229 string result = await Do(db => db.StringGetAsync(key)); 230 return ConvertObj<T>(result); 231 } 232 233 /// <summary> 234 /// 为数字增长val 235 /// </summary> 236 /// <param name="key"></param> 237 /// <param name="val">可以为负</param> 238 /// <returns>增长后的值</returns> 239 public async Task<double> StringIncrementAsync(string key, double val = 1) 240 { 241 key = AddSysCustomKey(key); 242 return await Do(db => db.StringIncrementAsync(key, val)); 243 } 244 245 /// <summary> 246 /// 为数字减少val 247 /// </summary> 248 /// <param name="key"></param> 249 /// <param name="val">可以为负</param> 250 /// <returns>减少后的值</returns> 251 public async Task<double> StringDecrementAsync(string key, double val = 1) 252 { 253 key = AddSysCustomKey(key); 254 return await Do(db => db.StringDecrementAsync(key, val)); 255 } 256 257 #endregion 异步方法 258 259 #endregion String 260 261 #region Hash 262 263 #region 同步方法 264 265 /// <summary> 266 /// 判断某个数据是否已经被缓存 267 /// </summary> 268 /// <param name="key"></param> 269 /// <param name="dataKey"></param> 270 /// <returns></returns> 271 public bool HashExists(string key, string dataKey) 272 { 273 key = AddSysCustomKey(key); 274 return Do(db => db.HashExists(key, dataKey)); 275 } 276 277 /// <summary> 278 /// 存储数据到hash表 279 /// </summary> 280 /// <typeparam name="T"></typeparam> 281 /// <param name="key"></param> 282 /// <param name="dataKey"></param> 283 /// <param name="t"></param> 284 /// <returns></returns> 285 public bool HashSet<T>(string key, string dataKey, T t) 286 { 287 key = AddSysCustomKey(key); 288 return Do(db => 289 { 290 string json = ConvertJson(t); 291 return db.HashSet(key, dataKey, json); 292 }); 293 } 294 295 /// <summary> 296 /// 移除hash中的某值 297 /// </summary> 298 /// <param name="key"></param> 299 /// <param name="dataKey"></param> 300 /// <returns></returns> 301 public bool HashDelete(string key, string dataKey) 302 { 303 key = AddSysCustomKey(key); 304 return Do(db => db.HashDelete(key, dataKey)); 305 } 306 307 /// <summary> 308 /// 移除hash中的多个值 309 /// </summary> 310 /// <param name="key"></param> 311 /// <param name="dataKeys"></param> 312 /// <returns></returns> 313 public long HashDelete(string key, List<RedisValue> dataKeys) 314 { 315 key = AddSysCustomKey(key); 316 //List<RedisValue> dataKeys1 = new List<RedisValue>() {"1","2"}; 317 return Do(db => db.HashDelete(key, dataKeys.ToArray())); 318 } 319 320 /// <summary> 321 /// 从hash表获取数据 322 /// </summary> 323 /// <typeparam name="T"></typeparam> 324 /// <param name="key"></param> 325 /// <param name="dataKey"></param> 326 /// <returns></returns> 327 public T HashGet<T>(string key, string dataKey) 328 { 329 key = AddSysCustomKey(key); 330 return Do(db => 331 { 332 string value = db.HashGet(key, dataKey); 333 return ConvertObj<T>(value); 334 }); 335 } 336 337 /// <summary> 338 /// 为数字增长val 339 /// </summary> 340 /// <param name="key"></param> 341 /// <param name="dataKey"></param> 342 /// <param name="val">可以为负</param> 343 /// <returns>增长后的值</returns> 344 public double HashIncrement(string key, string dataKey, double val = 1) 345 { 346 key = AddSysCustomKey(key); 347 return Do(db => db.HashIncrement(key, dataKey, val)); 348 } 349 350 /// <summary> 351 /// 为数字减少val 352 /// </summary> 353 /// <param name="key"></param> 354 /// <param name="dataKey"></param> 355 /// <param name="val">可以为负</param> 356 /// <returns>减少后的值</returns> 357 public double HashDecrement(string key, string dataKey, double val = 1) 358 { 359 key = AddSysCustomKey(key); 360 return Do(db => db.HashDecrement(key, dataKey, val)); 361 } 362 363 /// <summary> 364 /// 获取hashkey所有Redis key 365 /// </summary> 366 /// <typeparam name="T"></typeparam> 367 /// <param name="key"></param> 368 /// <returns></returns> 369 public List<T> HashKeys<T>(string key) 370 { 371 key = AddSysCustomKey(key); 372 return Do(db => 373 { 374 RedisValue[] values = db.HashKeys(key); 375 return ConvetList<T>(values); 376 }); 377 } 378 379 #endregion 同步方法 380 381 #region 异步方法 382 383 /// <summary> 384 /// 判断某个数据是否已经被缓存 385 /// </summary> 386 /// <param name="key"></param> 387 /// <param name="dataKey"></param> 388 /// <returns></returns> 389 public async Task<bool> HashExistsAsync(string key, string dataKey) 390 { 391 key = AddSysCustomKey(key); 392 return await Do(db => db.HashExistsAsync(key, dataKey)); 393 } 394 395 /// <summary> 396 /// 存储数据到hash表 397 /// </summary> 398 /// <typeparam name="T"></typeparam> 399 /// <param name="key"></param> 400 /// <param name="dataKey"></param> 401 /// <param name="t"></param> 402 /// <returns></returns> 403 public async Task<bool> HashSetAsync<T>(string key, string dataKey, T t) 404 { 405 key = AddSysCustomKey(key); 406 return await Do(db => 407 { 408 string json = ConvertJson(t); 409 return db.HashSetAsync(key, dataKey, json); 410 }); 411 } 412 413 /// <summary> 414 /// 移除hash中的某值 415 /// </summary> 416 /// <param name="key"></param> 417 /// <param name="dataKey"></param> 418 /// <returns></returns> 419 public async Task<bool> HashDeleteAsync(string key, string dataKey) 420 { 421 key = AddSysCustomKey(key); 422 return await Do(db => db.HashDeleteAsync(key, dataKey)); 423 } 424 425 /// <summary> 426 /// 移除hash中的多个值 427 /// </summary> 428 /// <param name="key"></param> 429 /// <param name="dataKeys"></param> 430 /// <returns></returns> 431 public async Task<long> HashDeleteAsync(string key, List<RedisValue> dataKeys) 432 { 433 key = AddSysCustomKey(key); 434 //List<RedisValue> dataKeys1 = new List<RedisValue>() {"1","2"}; 435 return await Do(db => db.HashDeleteAsync(key, dataKeys.ToArray())); 436 } 437 438 /// <summary> 439 /// 从hash表获取数据 440 /// </summary> 441 /// <typeparam name="T"></typeparam> 442 /// <param name="key"></param> 443 /// <param name="dataKey"></param> 444 /// <returns></returns> 445 public async Task<T> HashGeAsync<T>(string key, string dataKey) 446 { 447 key = AddSysCustomKey(key); 448 string value = await Do(db => db.HashGetAsync(key, dataKey)); 449 return ConvertObj<T>(value); 450 } 451 452 /// <summary> 453 /// 为数字增长val 454 /// </summary> 455 /// <param name="key"></param> 456 /// <param name="dataKey"></param> 457 /// <param name="val">可以为负</param> 458 /// <returns>增长后的值</returns> 459 public async Task<double> HashIncrementAsync(string key, string dataKey, double val = 1) 460 { 461 key = AddSysCustomKey(key); 462 return await Do(db => db.HashIncrementAsync(key, dataKey, val)); 463 } 464 465 /// <summary> 466 /// 为数字减少val 467 /// </summary> 468 /// <param name="key"></param> 469 /// <param name="dataKey"></param> 470 /// <param name="val">可以为负</param> 471 /// <returns>减少后的值</returns> 472 public async Task<double> HashDecrementAsync(string key, string dataKey, double val = 1) 473 { 474 key = AddSysCustomKey(key); 475 return await Do(db => db.HashDecrementAsync(key, dataKey, val)); 476 } 477 478 /// <summary> 479 /// 获取hashkey所有Redis key 480 /// </summary> 481 /// <typeparam name="T"></typeparam> 482 /// <param name="key"></param> 483 /// <returns></returns> 484 public async Task<List<T>> HashKeysAsync<T>(string key) 485 { 486 key = AddSysCustomKey(key); 487 RedisValue[] values = await Do(db => db.HashKeysAsync(key)); 488 return ConvetList<T>(values); 489 } 490 491 #endregion 异步方法 492 493 #endregion Hash 494 495 #region List 496 497 #region 同步方法 498 499 /// <summary> 500 /// 移除指定ListId的内部List的值 501 /// </summary> 502 /// <param name="key"></param> 503 /// <param name="value"></param> 504 public void ListRemove<T>(string key, T value) 505 { 506 key = AddSysCustomKey(key); 507 Do(db => db.ListRemove(key, ConvertJson(value))); 508 } 509 510 /// <summary> 511 /// 获取指定key的List 512 /// </summary> 513 /// <param name="key"></param> 514 /// <returns></returns> 515 public List<T> ListRange<T>(string key) 516 { 517 key = AddSysCustomKey(key); 518 return Do(redis => 519 { 520 var values = redis.ListRange(key); 521 return ConvetList<T>(values); 522 }); 523 } 524 525 /// <summary> 526 /// 入队 527 /// </summary> 528 /// <param name="key"></param> 529 /// <param name="value"></param> 530 public void ListRightPush<T>(string key, T value) 531 { 532 key = AddSysCustomKey(key); 533 Do(db => db.ListRightPush(key, ConvertJson(value))); 534 } 535 536 /// <summary> 537 /// 出队 538 /// </summary> 539 /// <typeparam name="T"></typeparam> 540 /// <param name="key"></param> 541 /// <returns></returns> 542 public T ListRightPop<T>(string key) 543 { 544 key = AddSysCustomKey(key); 545 return Do(db => 546 { 547 var value = db.ListRightPop(key); 548 return ConvertObj<T>(value); 549 }); 550 } 551 552 /// <summary> 553 /// 入栈 554 /// </summary> 555 /// <typeparam name="T"></typeparam> 556 /// <param name="key"></param> 557 /// <param name="value"></param> 558 public void ListLeftPush<T>(string key, T value) 559 { 560 key = AddSysCustomKey(key); 561 Do(db => db.ListLeftPush(key, ConvertJson(value))); 562 } 563 564 /// <summary> 565 /// 出栈 566 /// </summary> 567 /// <typeparam name="T"></typeparam> 568 /// <param name="key"></param> 569 /// <returns></returns> 570 public T ListLeftPop<T>(string key) 571 { 572 key = AddSysCustomKey(key); 573 return Do(db => 574 { 575 var value = db.ListLeftPop(key); 576 return ConvertObj<T>(value); 577 }); 578 } 579 580 /// <summary> 581 /// 获取集合中的数量 582 /// </summary> 583 /// <param name="key"></param> 584 /// <returns></returns> 585 public long ListLength(string key) 586 { 587 key = AddSysCustomKey(key); 588 return Do(redis => redis.ListLength(key)); 589 } 590 591 #endregion 同步方法 592 593 #region 异步方法 594 595 /// <summary> 596 /// 移除指定ListId的内部List的值 597 /// </summary> 598 /// <param name="key"></param> 599 /// <param name="value"></param> 600 public async Task<long> ListRemoveAsync<T>(string key, T value) 601 { 602 key = AddSysCustomKey(key); 603 return await Do(db => db.ListRemoveAsync(key, ConvertJson(value))); 604 } 605 606 /// <summary> 607 /// 获取指定key的List 608 /// </summary> 609 /// <param name="key"></param> 610 /// <returns></returns> 611 public async Task<List<T>> ListRangeAsync<T>(string key) 612 { 613 key = AddSysCustomKey(key); 614 var values = await Do(redis => redis.ListRangeAsync(key)); 615 return ConvetList<T>(values); 616 } 617 618 /// <summary> 619 /// 入队 620 /// </summary> 621 /// <param name="key"></param> 622 /// <param name="value"></param> 623 public async Task<long> ListRightPushAsync<T>(string key, T value) 624 { 625 key = AddSysCustomKey(key); 626 return await Do(db => db.ListRightPushAsync(key, ConvertJson(value))); 627 } 628 629 /// <summary> 630 /// 出队 631 /// </summary> 632 /// <typeparam name="T"></typeparam> 633 /// <param name="key"></param> 634 /// <returns></returns> 635 public async Task<T> ListRightPopAsync<T>(string key) 636 { 637 key = AddSysCustomKey(key); 638 var value = await Do(db => db.ListRightPopAsync(key)); 639 return ConvertObj<T>(value); 640 } 641 642 /// <summary> 643 /// 入栈 644 /// </summary> 645 /// <typeparam name="T"></typeparam> 646 /// <param name="key"></param> 647 /// <param name="value"></param> 648 public async Task<long> ListLeftPushAsync<T>(string key, T value) 649 { 650 key = AddSysCustomKey(key); 651 return await Do(db => db.ListLeftPushAsync(key, ConvertJson(value))); 652 } 653 654 /// <summary> 655 /// 出栈 656 /// </summary> 657 /// <typeparam name="T"></typeparam> 658 /// <param name="key"></param> 659 /// <returns></returns> 660 public async Task<T> ListLeftPopAsync<T>(string key) 661 { 662 key = AddSysCustomKey(key); 663 var value = await Do(db => db.ListLeftPopAsync(key)); 664 return ConvertObj<T>(value); 665 } 666 667 /// <summary> 668 /// 获取集合中的数量 669 /// </summary> 670 /// <param name="key"></param> 671 /// <returns></returns> 672 public async Task<long> ListLengthAsync(string key) 673 { 674 key = AddSysCustomKey(key); 675 return await Do(redis => redis.ListLengthAsync(key)); 676 } 677 678 #endregion 异步方法 679 680 #endregion List 681 682 #region SortedSet 有序集合 683 684 #region 同步方法 685 686 /// <summary> 687 /// 添加 688 /// </summary> 689 /// <param name="key"></param> 690 /// <param name="value"></param> 691 /// <param name="score"></param> 692 public bool SortedSetAdd<T>(string key, T value, double score) 693 { 694 key = AddSysCustomKey(key); 695 return Do(redis => redis.SortedSetAdd(key, ConvertJson<T>(value), score)); 696 } 697 698 /// <summary> 699 /// 删除 700 /// </summary> 701 /// <param name="key"></param> 702 /// <param name="value"></param> 703 public bool SortedSetRemove<T>(string key, T value) 704 { 705 key = AddSysCustomKey(key); 706 return Do(redis => redis.SortedSetRemove(key, ConvertJson(value))); 707 } 708 709 /// <summary> 710 /// 获取全部 711 /// </summary> 712 /// <param name="key"></param> 713 /// <returns></returns> 714 public List<T> SortedSetRangeByRank<T>(string key) 715 { 716 key = AddSysCustomKey(key); 717 return Do(redis => 718 { 719 var values = redis.SortedSetRangeByRank(key); 720 return ConvetList<T>(values); 721 }); 722 } 723 724 /// <summary> 725 /// 获取集合中的数量 726 /// </summary> 727 /// <param name="key"></param> 728 /// <returns></returns> 729 public long SortedSetLength(string key) 730 { 731 key = AddSysCustomKey(key); 732 return Do(redis => redis.SortedSetLength(key)); 733 } 734 735 #endregion 同步方法 736 737 #region 异步方法 738 739 /// <summary> 740 /// 添加 741 /// </summary> 742 /// <param name="key"></param> 743 /// <param name="value"></param> 744 /// <param name="score"></param> 745 public async Task<bool> SortedSetAddAsync<T>(string key, T value, double score) 746 { 747 key = AddSysCustomKey(key); 748 return await Do(redis => redis.SortedSetAddAsync(key, ConvertJson<T>(value), score)); 749 } 750 751 /// <summary> 752 /// 删除 753 /// </summary> 754 /// <param name="key"></param> 755 /// <param name="value"></param> 756 public async Task<bool> SortedSetRemoveAsync<T>(string key, T value) 757 { 758 key = AddSysCustomKey(key); 759 return await Do(redis => redis.SortedSetRemoveAsync(key, ConvertJson(value))); 760 } 761 762 /// <summary> 763 /// 获取全部 764 /// </summary> 765 /// <param name="key"></param> 766 /// <returns></returns> 767 public async Task<List<T>> SortedSetRangeByRankAsync<T>(string key) 768 { 769 key = AddSysCustomKey(key); 770 var values = await Do(redis => redis.SortedSetRangeByRankAsync(key)); 771 return ConvetList<T>(values); 772 } 773 774 /// <summary> 775 /// 获取集合中的数量 776 /// </summary> 777 /// <param name="key"></param> 778 /// <returns></returns> 779 public async Task<long> SortedSetLengthAsync(string key) 780 { 781 key = AddSysCustomKey(key); 782 return await Do(redis => redis.SortedSetLengthAsync(key)); 783 } 784 785 #endregion 异步方法 786 787 #endregion SortedSet 有序集合 788 789 #region key 790 791 /// <summary> 792 /// 删除单个key 793 /// </summary> 794 /// <param name="key">redis key</param> 795 /// <returns>是否删除成功</returns> 796 public bool KeyDelete(string key) 797 { 798 key = AddSysCustomKey(key); 799 return Do(db => db.KeyDelete(key)); 800 } 801 802 /// <summary> 803 /// 删除多个key 804 /// </summary> 805 /// <param name="keys">rediskey</param> 806 /// <returns>成功删除的个数</returns> 807 public long KeyDelete(List<string> keys) 808 { 809 List<string> newKeys = keys.Select(AddSysCustomKey).ToList(); 810 return Do(db => db.KeyDelete(ConvertRedisKeys(newKeys))); 811 } 812 813 /// <summary> 814 /// 判断key是否存储 815 /// </summary> 816 /// <param name="key">redis key</param> 817 /// <returns></returns> 818 public bool KeyExists(string key) 819 { 820 key = AddSysCustomKey(key); 821 return Do(db => db.KeyExists(key)); 822 } 823 824 /// <summary> 825 /// 重新命名key 826 /// </summary> 827 /// <param name="key">就的redis key</param> 828 /// <param name="newKey">新的redis key</param> 829 /// <returns></returns> 830 public bool KeyRename(string key, string newKey) 831 { 832 key = AddSysCustomKey(key); 833 return Do(db => db.KeyRename(key, newKey)); 834 } 835 836 /// <summary> 837 /// 设置Key的时间 838 /// </summary> 839 /// <param name="key">redis key</param> 840 /// <param name="expiry"></param> 841 /// <returns></returns> 842 public bool KeyExpire(string key, TimeSpan? expiry = default(TimeSpan?)) 843 { 844 key = AddSysCustomKey(key); 845 return Do(db => db.KeyExpire(key, expiry)); 846 } 847 848 #endregion key 849 850 #region 发布订阅 851 852 /// <summary> 853 /// Redis发布订阅 订阅 854 /// </summary> 855 /// <param name="subChannel"></param> 856 /// <param name="handler"></param> 857 public void Subscribe(string subChannel, Action<RedisChannel, RedisValue> handler = null) 858 { 859 ISubscriber sub = _conn.GetSubscriber(); 860 sub.Subscribe(subChannel, (channel, message) => 861 { 862 if (handler == null) 863 { 864 Console.WriteLine(subChannel + " 订阅收到消息:" + message); 865 } 866 else 867 { 868 handler(channel, message); 869 } 870 }); 871 } 872 873 /// <summary> 874 /// Redis发布订阅 发布 875 /// </summary> 876 /// <typeparam name="T"></typeparam> 877 /// <param name="channel"></param> 878 /// <param name="msg"></param> 879 /// <returns></returns> 880 public long Publish<T>(string channel, T msg) 881 { 882 ISubscriber sub = _conn.GetSubscriber(); 883 return sub.Publish(channel, ConvertJson(msg)); 884 } 885 886 /// <summary> 887 /// Redis发布订阅 取消订阅 888 /// </summary> 889 /// <param name="channel"></param> 890 public void Unsubscribe(string channel) 891 { 892 ISubscriber sub = _conn.GetSubscriber(); 893 sub.Unsubscribe(channel); 894 } 895 896 /// <summary> 897 /// Redis发布订阅 取消全部订阅 898 /// </summary> 899 public void UnsubscribeAll() 900 { 901 ISubscriber sub = _conn.GetSubscriber(); 902 sub.UnsubscribeAll(); 903 } 904 905 #endregion 发布订阅 906 907 #region 其他 908 909 public ITransaction CreateTransaction() 910 { 911 return GetDatabase().CreateTransaction(); 912 } 913 914 public IDatabase GetDatabase() 915 { 916 return _conn.GetDatabase(DbNum); 917 } 918 919 public IServer GetServer(string hostAndPort) 920 { 921 return _conn.GetServer(hostAndPort); 922 } 923 924 /// <summary> 925 /// 设置前缀 926 /// </summary> 927 /// <param name="customKey"></param> 928 public void SetSysCustomKey(string customKey) 929 { 930 CustomKey = customKey; 931 } 932 933 #endregion 其他 934 935 #region 辅助方法 936 937 private string AddSysCustomKey(string oldKey) 938 { 939 var prefixKey = CustomKey ?? RedisConnectionHelp.SysCustomKey; 940 return prefixKey + oldKey; 941 } 942 943 private T Do<T>(Func<IDatabase, T> func) 944 { 945 var database = _conn.GetDatabase(DbNum); 946 return func(database); 947 } 948 949 public string ConvertJson<T>(T value) 950 { 951 string result = value is string ? value.ToString() : JsonConvert.SerializeObject(value); 952 return result; 953 } 954 955 public T ConvertObj<T>(RedisValue value) 956 { 957 return JsonConvert.DeserializeObject<T>(value); 958 } 959 960 private List<T> ConvetList<T>(RedisValue[] values) 961 { 962 List<T> result = new List<T>(); 963 foreach (var item in values) 964 { 965 var model = ConvertObj<T>(item); 966 result.Add(model); 967 } 968 return result; 969 } 970 971 private RedisKey[] ConvertRedisKeys(List<string> redisKeys) 972 { 973 return redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray(); 974 } 975 976 #endregion 辅助方法 977 978 #region 批量操作 979 980 #region 批量写Key-Value 981 /// <summary> 982 /// 批量写Key-Value 983 /// </summary> 984 /// <param name="keyValues"></param> 985 /// <returns></returns> 986 public bool StringWriteBatch(List<KeyValuePair<RedisKey, RedisValue>> keyValues) 987 { 988 bool result = false; 989 try 990 { 991 var db = _conn.GetDatabase(); 992 var batch = db.CreateBatch(); 993 foreach (var item in keyValues) 994 { 995 batch.StringSetAsync(item.Key, item.Value); 996 } 997 batch.Execute(); 998 result = true; 999 } 1000 catch 1001 { 1002 } 1003 return result; 1004 } 1005 #endregion 1006 1007 #region 批量读Key-Value 1008 /// <summary> 1009 /// 批量读Key-Value 1010 /// </summary> 1011 /// <typeparam name="T"></typeparam> 1012 /// <param name="lstKey"></param> 1013 /// <returns></returns> 1014 public List<T> StringReadBatch<T>(List<RedisKey> lstKey) 1015 { 1016 List<Task<RedisValue>> valueList = new List<Task<RedisValue>>(); 1017 List<T> lstResult = new List<T>(); 1018 try 1019 { 1020 var db = _conn.GetDatabase(); 1021 var batch = db.CreateBatch(); 1022 foreach (var item in lstKey) 1023 { 1024 Task<RedisValue> value = batch.StringGetAsync(item); 1025 valueList.Add(value); 1026 } 1027 batch.Execute(); 1028 1029 foreach (var item in valueList) 1030 { 1031 T t = ConvertObj<T>(item.Result); 1032 lstResult.Add(t); 1033 } 1034 } 1035 catch 1036 { 1037 } 1038 return lstResult; 1039 } 1040 1041 /// <summary> 1042 /// 批量读操作,返回DataSe集合 1043 /// </summary> 1044 /// <param name="lstKey"></param> 1045 /// <returns></returns> 1046 public DataSet StringReadBatch(List<RedisKey> lstKey) 1047 { 1048 if (lstKey == null || lstKey.Count < 1) return null; 1049 List<Task<RedisValue>> valueList = new List<Task<RedisValue>>(); 1050 DataSet ds = new DataSet(); 1051 try 1052 { 1053 var db = _conn.GetDatabase(); 1054 var batch = db.CreateBatch(); 1055 foreach (var item in lstKey) 1056 { 1057 Task<RedisValue> value = batch.StringGetAsync(item); 1058 valueList.Add(value); 1059 } 1060 batch.Execute(); 1061 1062 foreach (var item in valueList) 1063 { 1064 DataTable t = ConvertObj<DataTable>(item.Result); 1065 ds.Tables.Add(t); 1066 } 1067 } 1068 catch 1069 { 1070 } 1071 return ds; 1072 } 1073 #endregion 1074 1075 #region 批量写Hash 1076 /// <summary> 1077 /// 批量写Hash 1078 /// </summary> 1079 /// <param name="keyValues"></param> 1080 /// <returns></returns> 1081 public bool HashWriteBatch(List<KeyValuePair<RedisKey, HashEntry[]>> keyValues) 1082 { 1083 bool result = false; 1084 try 1085 { 1086 var db = _conn.GetDatabase(); 1087 var batch = db.CreateBatch(); 1088 foreach (var item in keyValues) 1089 { 1090 batch.HashSetAsync(item.Key, item.Value); 1091 } 1092 batch.Execute(); 1093 result = true; 1094 } 1095 catch 1096 { 1097 } 1098 return result; 1099 } 1100 #endregion 1101 1102 #region 批量读Hash 1103 /// <summary> 1104 /// 批量读Hash 1105 /// </summary> 1106 ///<param name="keyFields">hash键和field</param> 1107 /// <returns></returns> 1108 public List<T> HashReadBatch<T>(List<KeyValuePair<RedisKey, RedisValue[]>> keyFields) 1109 { 1110 List<Task<RedisValue[]>> valueList = new List<Task<RedisValue[]>>(); 1111 List<T> lstResult = new List<T>(); 1112 try 1113 { 1114 var db = _conn.GetDatabase(); 1115 var batch = db.CreateBatch(); 1116 foreach (var item in keyFields) 1117 { 1118 Task<RedisValue[]> value = batch.HashGetAsync(item.Key, item.Value); 1119 valueList.Add(value); 1120 } 1121 batch.Execute(); 1122 1123 foreach (var item in valueList) 1124 { 1125 if (item.Result == null) continue; 1126 foreach (var redisValue in item.Result) 1127 { 1128 T t = ConvertObj<T>(redisValue); 1129 lstResult.Add(t); 1130 } 1131 } 1132 } 1133 catch 1134 { 1135 } 1136 return lstResult; 1137 } 1138 #endregion 1139 1140 #endregion
3)单例模式
1 /// <summary> 2 /// ConnectionMultiplexer对象管理帮助类 3 /// </summary> 4 public static class RedisConnectionHelp 5 { 6 //系统自定义Key前缀 7 public static readonly string SysCustomKey = ConfigurationManager.AppSettings["redisKey"] ?? ""; 8 9 //"127.0.0.1:6379,allowadmin=true 10 private static readonly string RedisConnectionString = ConfigurationManager.ConnectionStrings["RedisExchangeHosts"].ConnectionString; 11 12 private static readonly object Locker = new object(); 13 private static ConnectionMultiplexer _instance; 14 private static readonly ConcurrentDictionary<string, ConnectionMultiplexer> ConnectionCache = new ConcurrentDictionary<string, ConnectionMultiplexer>(); 15 16 /// <summary> 17 /// 单例获取 18 /// </summary> 19 public static ConnectionMultiplexer Instance 20 { 21 get 22 { 23 if (_instance == null) 24 { 25 lock (Locker) 26 { 27 if (_instance == null || !_instance.IsConnected) 28 { 29 _instance = GetManager(); 30 } 31 } 32 } 33 return _instance; 34 } 35 } 36 37 /// <summary> 38 /// 缓存获取 39 /// </summary> 40 /// <param name="connectionString"></param> 41 /// <returns></returns> 42 public static ConnectionMultiplexer GetConnectionMultiplexer(string connectionString) 43 { 44 if (!ConnectionCache.ContainsKey(connectionString)) 45 { 46 ConnectionCache[connectionString] = GetManager(connectionString); 47 } 48 return ConnectionCache[connectionString]; 49 } 50 51 private static ConnectionMultiplexer GetManager(string connectionString = null) 52 { 53 connectionString = connectionString ?? RedisConnectionString; 54 var connect = ConnectionMultiplexer.Connect(connectionString); 55 56 //注册如下事件 57 connect.ConnectionFailed += MuxerConnectionFailed; 58 connect.ConnectionRestored += MuxerConnectionRestored; 59 connect.ErrorMessage += MuxerErrorMessage; 60 connect.ConfigurationChanged += MuxerConfigurationChanged; 61 connect.HashSlotMoved += MuxerHashSlotMoved; 62 connect.InternalError += MuxerInternalError; 63 64 return connect; 65 } 66 67 #region 事件 68 69 /// <summary> 70 /// 配置更改时 71 /// </summary> 72 /// <param name="sender"></param> 73 /// <param name="e"></param> 74 private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e) 75 { 76 Console.WriteLine("Configuration changed: " + e.EndPoint); 77 } 78 79 /// <summary> 80 /// 发生错误时 81 /// </summary> 82 /// <param name="sender"></param> 83 /// <param name="e"></param> 84 private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e) 85 { 86 Console.WriteLine("ErrorMessage: " + e.Message); 87 } 88 89 /// <summary> 90 /// 重新建立连接之前的错误 91 /// </summary> 92 /// <param name="sender"></param> 93 /// <param name="e"></param> 94 private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e) 95 { 96 Console.WriteLine("ConnectionRestored: " + e.EndPoint); 97 } 98 99 /// <summary> 100 /// 连接失败 , 如果重新连接成功你将不会收到这个通知 101 /// </summary> 102 /// <param name="sender"></param> 103 /// <param name="e"></param> 104 private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e) 105 { 106 Console.WriteLine("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message))); 107 } 108 109 /// <summary> 110 /// 更改集群 111 /// </summary> 112 /// <param name="sender"></param> 113 /// <param name="e"></param> 114 private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e) 115 { 116 Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint); 117 } 118 119 /// <summary> 120 /// redis类库错误 121 /// </summary> 122 /// <param name="sender"></param> 123 /// <param name="e"></param> 124 private static void MuxerInternalError(object sender, InternalErrorEventArgs e) 125 { 126 Console.WriteLine("InternalError:Message" + e.Exception.Message); 127 } 128 129 #endregion 事件 130 }
4)app.config中增加redis连接字符串
<connectionStrings> <add name="RedisExchangeHosts" connectionString="127.0.0.1:6379,password=xxxxxx"/> </connectionStrings>
反射实现Model修改前后的内容对比 【API调用】腾讯云短信 Windows操作系统下Redis服务安装图文详解 Redis入门学习的更多相关文章
- 反射实现Model修改前后的内容对比
在开发过程中,我们会遇到这样一个问题,编辑了一个对象之后,我们想要把这个对象修改了哪些内容保存下来,以便将来查看和追责. 首先我们要创建一个User类 public class User { priv ...
- 腾讯云短信 nodejs 接入, 通过验证码修改手机示例
腾讯云短信 nodejs 接入, 通过验证码修改手机示例 参考:腾讯云短信文档国内短信快速入门qcloudsms Node.js SDK文档中心>短信>错误码 nodejs sdk 使用示 ...
- TortoiseGit学习系列之TortoiseGit基本操作修改提交项目(图文详解)
前面博客 TortoiseGit学习系列之TortoiseGit基本操作克隆项目(图文详解) TortoiseGit基本操作修改提交项目 项目克隆完成后(可以将克隆 clone 理解为 下载,检出 c ...
- Android(java)学习笔记254:ContentProvider使用之内容观察者(观察发出去的短信)
1.新建一个案例如下: 2. 不需要添加权限,同时这里布局文件不做修改,来到MainActivity,如下: package com.itheima.sendsmslistener; import a ...
- Android(java)学习笔记198:ContentProvider使用之内容观察者(观察发出去的短信)
1.新建一个案例如下: 2. 不需要添加权限,同时这里布局文件不做修改,来到MainActivity,如下: package com.itheima.sendsmslistener; import a ...
- Java反射详解:入门+使用+原理+应用场景
反射非常强大和有用,现在市面上绝大部分框架(spring.mybatis.rocketmq等等)中都有反射的影子,反射机制在框架设计中占有举足轻重的作用. 所以,在你Java进阶的道路上,你需要掌握好 ...
- 全网最详细的实用的搜索工具Listary和Everything对比的区别【堪称比Everything要好】(图文详解)
不多说,直接上干货! 引言 无论是工作还是科研,我们都希望工作既快又好,然而大多数时候却迷失在繁杂的重复劳动中,久久无法摆脱繁杂的事情. 你是不是曾有这样一种想法:如果我有哆啦A梦的口袋,只要拿出 ...
- ubuntu系统复制到其他地方或克隆后,如何正确修改IP及MAC地址的解决方案(图文详解)
修改ip地址 永久修改MAC地址 方法一: 1)编辑“/etc/init.d/rc.local”文件(sudo gedit /etc/init.d/rc.local) 2)在此配置文件的最后面加上如( ...
- Navicat for Mysql修改MySQL数据库密码,图文详解
1.创建一个连接 2.打开连接 3.按照图示123依次点击 4.输入新密码 5.查看实现修改密码功能的SQL语句(此步骤非必须) 6.最关键的一步:点击保存 7.出现如下现象,恭喜你,修改密码成功! ...
随机推荐
- Python+Selenium 自动化测试获取测试报告内容并发送邮件
这里封装一个send_mail()方法,用于测试完成后读取测试报告内容,并将测试结果通过邮件发送到接收人 # coding: utf-8 import smtplib from email.mime. ...
- C#面试问题及答案
1.遇到高并发的问题如何解决? 优化SQL语句 多线程 分布式服务器 集群 拆表2.Dictionary和ConurrentDictionary的区别? 后者是线程安全的 前者适用于单线程3.Dict ...
- flatpickr插件的使用
flatpickr功能强大的日期时间选择器插件 日期格式化 <input class=flatpickr data-date-format="d-m-Y"> <i ...
- 获取url上的参数
var aa = '?name=hss&age=13'; function strToObj(str){ if(typeof str === 'undefi ...
- HDU1401 Solitaire
题目描述:8×8的棋盘上有4个棋子,棋子的运动方法如下:1.如果其上/下/左/右一格没有棋子,则可以去;2.如果其上/下/左/右一格有棋子,而且沿原方向再跳一步没有,则可以去. 给出初始结束位置,问8 ...
- 19Spring返回通知&异常通知&环绕通知
在前置通知和后置通知的基础上加上返回通知&异常通知&环绕通知 代码: package com.cn.spring.aop.impl; //加减乘除的接口类 public interfa ...
- LINUX:Contos7.0 / 7.2 LAMP+R 下载安装Apache篇
文章来源:http://www.cnblogs.com/hello-tl/p/7568803.html 更新时间:2017-09-21 15:38 简介 LAMP+R指Linux+Apache+Mys ...
- MapReduce架构与执行流程
一.MapReduce是用于解决什么问题的? 每一种技术的出现都是用来解决实际问题的,否则必将是昙花一现,那么MapReduce是用来解决什么实际的业务呢? 首先来看一下MapReduce官方定义: ...
- SQL SERVER占用CPU过高排查和优化
操作系统是Windows2008R2 ,数据库是SQL2014 64位. 近阶段服务器出现过几次死机,管理员反馈机器内存使用率100%导致机器卡死.于是做了个监测服务器的软件实时记录CPU数据,几日观 ...
- 关于c# .net爬虫
刚开始听到爬虫这两个字眼的时候感觉挺稀奇的,之前并没有接触过爬虫,正好这会手上没事,于是便百度了一下. 1.网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种 ...