高并发分布式系统中生成全局唯一(订单号)Id
1、GUID数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么通过组合的方式,保留GUID的10个字节,用另6个字节表示GUID生成的时间(DateTime),这样我们将时间信息与GUID组合起来,在保留GUID的唯一性的同时增加了有序性,以此来提高索引效率,在NHibernate中,COMB型主键的生成代码如下所示:
/// <summary> /// 保留GUID的10个字节,用另6个字节表示GUID生成的时间(DateTime)组合方式 /// </summary> /// <returns></returns> public static Guid GenerateComb() { byte[] guidArray = Guid.NewGuid().ToByteArray(); DateTime baseDate = new DateTime(1900, 1, 1); DateTime now = DateTime.Now; // Get the days and milliseconds which will be used to build //the byte string TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks); TimeSpan msecs = now.TimeOfDay; // Convert to a byte array // Note that SQL Server is accurate to 1/300th of a // millisecond so we divide by 3.333333 byte[] daysArray = BitConverter.GetBytes(days.Days); byte[] msecsArray = BitConverter.GetBytes((long) (msecs.TotalMilliseconds / 3.333333)); // Reverse the bytes to match SQL Servers ordering Array.Reverse(daysArray); Array.Reverse(msecsArray); // Copy the bytes into the guid Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2); Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4); return new Guid(guidArray); }
上述方法循环测试生成id如下图
结论:适合大型应用。即保留GUID的唯一性的同时增加了GUID有序性,提高了索引效率;解决了关联表业务问题;生成的Id不够友好;占据了32位。
2、将GUID转为了19位数字
/// <summary> /// 根据GUID获取19位的唯一数字序列 /// </summary> public static long GuidToLong() { byte[] buffer = Guid.NewGuid().ToByteArray(); return BitConverter.ToInt64(buffer, 0); }
上述方法循环测试生成id如下图
结论:适合大型应用,从业务上来说,有一个规则的编码能体现产品的专业成度。
js返回上一页并刷新、返回上一页、自动刷新页面
一、返回上一页并刷新
<a href="javascript:" onclick="self.location=document.referrer;">返回上一页并刷新</a> <a href="javascript:history.go(-1)">返回上一页</a> <a href="javascript:location.reload()">刷新当前页面</a> <a href="javascript:" onclick="history.go(-2); ">返回前两页</a> <a href="javascript:" onclick="history.back(); ">返回上一页</a>
二、自动刷新页面
<!-- 10指每隔5秒刷新一次页面 --> <meta http-equiv="refresh" content="5">
三、页面自动跳转
<!-- 5指隔5秒后跳转到http://www.baidu.com页面 --> <meta http-equiv="refresh" content="5;url=http://www.baidu.com">
四、页面跳转
<a href="javascript:" onclick="window.location.href='test.html'" >js跳转</a>
五、父子窗口之间的刷新
//刷新包含该框架的页面用 <script language=JavaScript> parent.location.reload(); </script> //子窗口刷新父窗口 <script language=JavaScript> self.opener.location.reload(); </script> ( 或者 <a href="javascript:opener.location.reload()">刷新</a> ) //刷新iframe另一个框架的页面用 <script language=JavaScript> parent.另一FrameID.location.reload(); </script>
父页面操作嵌套iframe子页面的HTML标签元素
一个页面A.html使用iframe嵌套一个页面B.html,在A页面写js操作B页面HTML元素,首先要获取到B页面document对象,才能对嵌套页面进行操作
请看一个实例,在A页面写js操作B页面div的内容:
A.html代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript" src="js/jquery-1.9.1.min.js" ></script> </head> <body > <iframe name="iframe1" src="B.html"></iframe> </body> </html> <script> window.onload=()=>{ $(window.frames["iframe1"].document).on("click","#btn",function(){ //window.frames["iframe1"].document获的iframe标签嵌套页面document对象 $(this).html("1123"); }) } </script>
B页面代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript" src="js/jquery-1.9.1.min.js" ></script> </head> <body id="body"> <div id="btn" >测试操作</div> </body> </html>
当点击 “测试操作” 时就这个文字就被修改成“1123”
.net判断System.Data.DataRow中是否包含某列
大家对将DataRow转成实体对象并不陌生,转成实体的时候一般都会加上这个判断 if (row["字段名"] != null && row["字段名"].ToString() != "") ,这个写法会存在一个问题,当row不存在这个字段时就会抛出异常,导致程序崩溃,这种情况在数据库频繁地修改出现的频率高,因为修改数据库时,代码里面转成实体的方法就不适用了,基于业务的不同可能存在多个转成实体的方法,这样修改数据库时,并修改代码的同时很容易遗漏修改,导致程序崩溃,特别是需求经常变动的项目(改数据库)。所以个人建议在判断里面加多一个逻辑条件:
if (row.Table.Columns.Contains("字段名") && row["字段名"] != null && row["字段名"].ToString() != "") //row.Table.Columns.Contains("字段名") 是判断row中是否存在该字段,存在返回true,否则返回 false
这个逻辑条件可以避免当row不存在该字段是出现的错误。
代码例子
实体类:
1 public class User 2 { 3 public int UserId { get; set; } 4 public string UserName { get; set; } 5 public int Age { set; get; } 6 }
转成实体类方法:
1 User userModel=new User(); 2 if (row.Table.Columns.Contains("UserId") && row["UserId"] !=null && row["UserId"].ToString() !="") 3 { 4 userModel.UserId = Convert.ToInt32(row["UserId"]); 5 } 6 if (row.Table.Columns.Contains("UserName") && row["UserName"] != null && row["UserName"].ToString() != "") 7 { 8 userModel.UserId = Convert.ToInt32(row["UserName"]); 9 } 10 if (row.Table.Columns.Contains("Age") && row["Age"] != null && row["Age"].ToString() != "") 11 { 12 userModel.UserId = Convert.ToInt32(row["Age"]); 13 } 14 return userModel; 15 }
.Net使用system.Security.Cryptography.RNGCryptoServiceProvider类与System.Random类生成随机数
.Net中我们通常使用Random类生成随机数,在一些场景下,我却发现Random生成的随机数并不可靠,在下面的例子中我们通过循环随机生成10个随机数:
for (int i = 0; i < 10; i++) { Random random1 = new Random(); Console.WriteLine(random1.Next()); }
测试生成随时基本都是相同的结果:
很显然上面的结果是不靠谱的,为什么会这样呢,因为微软的Random类,发现在C#中生成随机数使用的算法是线性同余法,这种算法生成的不是绝对随机,而是一种伪随机数,线性同余法算法的的公式是
:第n+1个数 = ( 第N个数 * a + b) % m ,公式中a、b和m分别为常数,是生成随机数的因子,如果之前从未通过同一个Random对象生成过随机数(也就是调用过Next方法),那么第N个随机数为将被指定为一个默认的常数,这个常数在创建一个Random类时被默认值指定,Random也提供一个构造函数允许开发者使用自己的随机数因子.
有人说要将 Random random1 = new Random(); 要放到循环的外面:
Random random2 = new Random(); for (int i = 0; i < 20; i++) { Console.WriteLine(random2.Next()); }
测试上面的代码执行的结果是这样的:
得到结果还是不靠谱的
有人说使用GUID产生填充因子:
for (int i = 0; i < 20; i++) { byte[] buffer = Guid.NewGuid().ToByteArray(); int iSeed = BitConverter.ToInt32(buffer, 0); Random random3 = new Random(iSeed); Console.WriteLine(random3.Next()); }
测试上面的代码得到的结果:
得到的结果还是不靠谱的。
为了生成更加可靠的随机数,微软在System.Security.Cryptography命名空间下提供一个名为system.Security.Cryptography.RNGCryptoServiceProvider的类,它采用系统当前的硬件信息、进程信息、线程信息、系统启动时间和当前精确时间作为填充因子,通过更好的算法生成高质量的随机数,它的使用方法如下所示:
for (int i = 0; i < 20; i++) { byte[] randomBytes = new byte[8]; System.Security.Cryptography.RNGCryptoServiceProvider rngServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider(); rngServiceProvider.GetBytes(randomBytes); int result = BitConverter.ToInt32(randomBytes, 0); result = System.Math.Abs(result); //求绝对值 Console.WriteLine(result); }
测试结果未发现重复的:
总结:
Random算法简单,性能较高,适用于随机性要求不高的情况,由于RNGCryptoServiceProvider在生成期间需要查询上面提到的几种系统因子,所以性能稍弱于Random类,但随机数质量高,可靠性更好。使用哪一种方式视情况而定