生成唯一值的方法很多,下面就不同环境下生成的唯一标识方法一一介绍,作为工作中的一次总结,有兴趣的可以自行测试:
一、在 .NET 中生成
1、直接用.NET Framework 提供的 Guid() 函数,此种方法使用非常广泛。GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的任何两台计算机都不会生成重复的 GUID 值(即保证所有机器都是唯一的)。关于GUID的介绍在此不作具体熬述,想深入了解可以自行查阅MSDN。代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 namespace ConsoleApplication1 6 { 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 string _guid = GetGuid(); 12 Console.WriteLine("唯一码:{0}\t长度为:{1}\n去掉连接符:{2}", _guid, _guid.Length, _guid.Replace("-", "")); 13 string uniqueIdString = GuidTo16String(); 14 Console.WriteLine("唯一码:{0}\t长度为:{1}", uniqueIdString, uniqueIdString.Length); 15 long uniqueIdLong = GuidToLongID(); 16 Console.WriteLine("唯一码:{0}\t长度为:{1}", uniqueIdLong, uniqueIdLong.ToString().Length); 17 } 18 /// <summary> 19 /// 由连字符分隔的32位数字 20 /// </summary> 21 /// <returns></returns> 22 private static string GetGuid() 23 { 24 System.Guid guid = new Guid(); 25 guid = Guid.NewGuid(); 26 return guid.ToString(); 27 } 28 /// <summary> 29 /// 根据GUID获取16位的唯一字符串 30 /// </summary> 31 /// <param name=\"guid\"></param> 32 /// <returns></returns> 33 public static string GuidTo16String() 34 { 35 long i = 1; 36 foreach (byte b in Guid.NewGuid().ToByteArray()) 37 i *= ((int)b + 1); 38 return string.Format("{0:x}", i - DateTime.Now.Ticks); 39 } 40 /// <summary> 41 /// 根据GUID获取19位的唯一数字序列 42 /// </summary> 43 /// <returns></returns> 44 public static long GuidToLongID() 45 { 46 byte[] buffer = Guid.NewGuid().ToByteArray(); 47 return BitConverter.ToInt64(buffer, 0); 48 } 49 } 50 }
2、用 DateTime.Now.ToString("yyyyMMddHHmmssms") 和 .NET Framework 提供的 RNGCryptoServiceProvider() 结合生成,代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 namespace ConsoleApplication1 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 string uniqueNum = GenerateOrderNumber(); 13 Console.WriteLine("唯一码:{0}\t 长度为:{1}", uniqueNum, uniqueNum.Length); 14 //测试是否会生成重复 15 Console.WriteLine("时间+RNGCryptoServiceProvider()结合生成的唯一值,如下:"); 16 string _tempNum = string.Empty; 17 for (int i = 0; i < 1000; i++) 18 { 19 string uNum = GenerateOrderNumber(); 20 Console.WriteLine(uNum); 21 if (string.Equals(uNum, _tempNum)) 22 { 23 Console.WriteLine("上值存在重复,按Enter键继续"); 24 Console.ReadKey(); 25 } 26 //Sleep当前线程,是为了延时,从而不产生重复值。可以把它注释掉测试看 27 Thread.Sleep(300); 28 _tempNum = uNum; 29 } 30 } 31 /// <summary> 32 /// 唯一订单号生成 33 /// </summary> 34 /// <returns></returns> 35 public static string GenerateOrderNumber() 36 { 37 string strDateTimeNumber = DateTime.Now.ToString("yyyyMMddHHmmssms"); 38 string strRandomResult = NextRandom(1000, 1).ToString(); 39 return strDateTimeNumber + strRandomResult; 40 } 41 /// <summary> 42 /// 参考:msdn上的RNGCryptoServiceProvider例子 43 /// </summary> 44 /// <param name="numSeeds"></param> 45 /// <param name="length"></param> 46 /// <returns></returns> 47 private static int NextRandom(int numSeeds, int length) 48 { 49 // Create a byte array to hold the random value. 50 byte[] randomNumber = new byte[length]; 51 // Create a new instance of the RNGCryptoServiceProvider. 52 System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); 53 // Fill the array with a random value. 54 rng.GetBytes(randomNumber); 55 // Convert the byte to an uint value to make the modulus operation easier. 56 uint randomResult = 0x0; 57 for (int i = 0; i < length; i++) 58 { 59 randomResult |= ((uint)randomNumber[i] << ((length - 1 - i) * 8)); 60 } 61 return (int)(randomResult % numSeeds) + 1; 62 } 63 } 64 }
3、用 [0-9A-Z] + Guid.NewGuid() 结合生成特定位数的唯一字符串,代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 namespace ConsoleApplication1 6 { 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 string uniqueText = GenerateUniqueText(8); 12 Console.WriteLine("唯一码:{0}\t 长度为:{1}", uniqueText, uniqueText.Length); 13 //测试是否会生成重复 14 Console.WriteLine("由[0-9A-Z] + NewGuid() 结合生成的唯一值,如下:"); 15 IList<string> list = new List<string>(); 16 for (int i = 1; i <= 1000; i++) 17 { 18 string _uT = GenerateUniqueText(8); 19 Console.WriteLine("{0}\t{1}", list.Count, _uT); 20 if (list.Contains(_uT)) 21 { 22 Console.WriteLine("{0}值存在重复", _uT); 23 Console.ReadKey(); 24 } 25 list.Add(_uT); 26 //if (i % 200 == 0) 27 //{ 28 //Console.WriteLine("没有重复,按Enter键往下看"); 29 //Console.ReadKey(); 30 //} 31 } 32 list.Clear(); 33 } 34 35 /// <summary> 36 /// 生成特定位数的唯一字符串 37 /// </summary> 38 /// <param name="num">特定位数</param> 39 /// <returns></returns> 40 public static string GenerateUniqueText(int num) 41 { 42 string randomResult = string.Empty; 43 string readyStr = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 44 char[] rtn = new char[num]; 45 Guid gid = Guid.NewGuid(); 46 var ba = gid.ToByteArray(); 47 for (var i = 0; i < num; i++) 48 { 49 rtn[i] = readyStr[((ba[i] + ba[num + i]) % 35)]; 50 } 51 foreach (char r in rtn) 52 { 53 randomResult += r; 54 } 55 return randomResult; 56 } 57 } 58 }
4、用单例模式实现,由[0-9a-z]组合生成的唯一值,此文不讨论单例模式的多种实现方式与性能问题,随便弄一种方式实现,代码如下:
Demo结构如图:
Program.cs 程序:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Collections; 6 using System.Xml; 7 namespace ConsoleApplication4 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 CreateID createID = CreateID.GetInstance(); 14 //测试是否会生成重复 15 Console.WriteLine("单例模式实现,由[0-9a-z]组合生成的唯一值,如下:"); 16 IList<string> list = new List<string>(); 17 for (int i = 1; i <= 1000000000; i++) 18 { 19 string strUniqueNum = createID.CreateUniqueID(); 20 Console.WriteLine("{0}\t{1}", list.Count, strUniqueNum); 21 if (list.Contains(strUniqueNum)) 22 { 23 Console.WriteLine("{0}值存在重复", strUniqueNum); 24 Console.ReadKey(); 25 } 26 list.Add(strUniqueNum); 27 if (i % 200 == 0) 28 { 29 Console.WriteLine("没有重复,按Enter键往下看"); 30 Console.ReadKey(); 31 } 32 } 33 list.Clear(); 34 } 35 } 36 /// <summary> 37 /// 单例模式实现 38 /// 唯一值由[0-9a-z]组合而成,且生成的每个ID不能重复 39 /// </summary> 40 public class CreateID 41 { 42 private static CreateID _instance; 43 private static readonly object syncRoot = new object(); 44 private EHashtable hashtable = new EHashtable(); 45 private string _strXMLURL = string.Empty; 46 private CreateID() 47 { 48 hashtable.Add("0", "0"); 49 hashtable.Add("1", "1"); 50 hashtable.Add("2", "2"); 51 hashtable.Add("3", "3"); 52 hashtable.Add("4", "4"); 53 hashtable.Add("5", "5"); 54 hashtable.Add("6", "6"); 55 hashtable.Add("7", "7"); 56 hashtable.Add("8", "8"); 57 hashtable.Add("9", "9"); 58 hashtable.Add("10", "a"); 59 hashtable.Add("11", "b"); 60 hashtable.Add("12", "c"); 61 hashtable.Add("13", "d"); 62 hashtable.Add("14", "e"); 63 hashtable.Add("15", "f"); 64 hashtable.Add("16", "g"); 65 hashtable.Add("17", "h"); 66 hashtable.Add("18", "i"); 67 hashtable.Add("19", "j"); 68 hashtable.Add("20", "k"); 69 hashtable.Add("21", "l"); 70 hashtable.Add("22", "m"); 71 hashtable.Add("23", "n"); 72 hashtable.Add("24", "o"); 73 hashtable.Add("25", "p"); 74 hashtable.Add("26", "q"); 75 hashtable.Add("27", "r"); 76 hashtable.Add("28", "s"); 77 hashtable.Add("29", "t"); 78 hashtable.Add("30", "u"); 79 hashtable.Add("31", "v"); 80 hashtable.Add("32", "w"); 81 hashtable.Add("33", "x"); 82 hashtable.Add("34", "y"); 83 hashtable.Add("35", "z"); 84 _strXMLURL = System.IO.Path.GetFullPath(@"..\..\") + "XMLs\\record.xml"; 85 86 } 87 public static CreateID GetInstance() 88 { 89 if (_instance == null) 90 { 91 lock (syncRoot) 92 { 93 if (_instance == null) 94 { 95 _instance = new CreateID(); 96 } 97 } 98 } 99 return _instance; 100 } 101 /// <summary> 102 /// 创建UniqueID 103 /// </summary> 104 /// <returns>UniqueID</returns> 105 public string CreateUniqueID() 106 { 107 long _uniqueid = GetGuidFromXml(); 108 return Convert10To36(_uniqueid); 109 } 110 /// <summary> 111 /// 获取UniqueID总记录,即获取得到的这个ID是第几个ID 112 /// 更新UniqueID使用的个数,用于下次使用 113 /// </summary> 114 /// <returns></returns> 115 private long GetGuidFromXml() 116 { 117 long record = 0; 118 XmlDocument xmldoc = new XmlDocument(); 119 xmldoc.Load(_strXMLURL); 120 XmlElement rootNode = xmldoc.DocumentElement; 121 //此次的个数值 122 record = Convert.ToInt64(rootNode["record"].InnerText); 123 //此次的个数值+1 == 下次的个数值 124 rootNode["record"].InnerText = Convert.ToString(record + 1); 125 xmldoc.Save(_strXMLURL); 126 return record; 127 } 128 /// <summary> 129 /// 10进制转36进制 130 /// </summary> 131 /// <param name="intNum10">10进制数</param> 132 /// <returns></returns> 133 private string Convert10To36(long intNum10) 134 { 135 string strNum36 = string.Empty; 136 long result = intNum10 / 36; 137 long remain = intNum10 % 36; 138 if (hashtable.ContainsKey(remain.ToString())) 139 strNum36 = hashtable[remain.ToString()].ToString() + strNum36; 140 intNum10 = result; 141 while (intNum10 / 36 != 0) 142 { 143 result = intNum10 / 36; 144 remain = intNum10 % 36; 145 if (hashtable.ContainsKey(remain.ToString())) 146 strNum36 = hashtable[remain.ToString()].ToString() + strNum36; 147 intNum10 = result; 148 } 149 if (intNum10 > 0 && intNum10 < 36) 150 { 151 if (hashtable.ContainsKey(intNum10.ToString())) 152 strNum36 = hashtable[intNum10.ToString()].ToString() + strNum36; 153 } 154 return strNum36; 155 } 156 } 157 /// <summary> 158 /// Summary description for EHashTable 159 /// </summary> 160 public class EHashtable : Hashtable 161 { 162 private ArrayList list = new ArrayList(); 163 public override void Add(object key, object value) 164 { 165 base.Add(key, value); 166 list.Add(key); 167 } 168 public override void Clear() 169 { 170 base.Clear(); 171 list.Clear(); 172 } 173 public override void Remove(object key) 174 { 175 base.Remove(key); 176 list.Remove(key); 177 } 178 public override ICollection Keys 179 { 180 get 181 { 182 return list; 183 } 184 } 185 } 186 }
XML:
1 <?xml version="1.0" encoding="utf-8"?> 2 <root> 3 <record id="record">1</record> 4 </root>
二、在JS中生成GUID,类似.NET中的 Guid.NewGuid(),代码如下:
1 function newGuid() { //方法一: 2 var guid = ""; 3 var n = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); 4 for (var i = 1; i <= 8; i++) { 5 guid += n; 6 } 7 return guid; 8 } 9 function newGuid() { //方法二: 10 var guid = ""; 11 for (var i = 1; i <= 32; i++) { 12 var n = Math.floor(Math.random() * 16.0).toString(16); 13 guid += n; 14 if ((i == 8) || (i == 12) || (i == 16) || (i == 20)) 15 guid += "-"; 16 } 17 return guid; 18 }
三、在SQL存储过程生成GUID,代码如下:
1 -- ============================================= 2 -- Author: JBen 3 -- Create date: 2012-06-05 4 -- Description: 生成唯一标识ID,公共存储过程,可设置在别的存储过程调用此存储过程传不同的前缀 5 -- ============================================= 6 ALTER PROCEDURE [dbo].[pro_CreateGuid] 7 @Prefix NVARCHAR(10), 8 @outputV_guid NVARCHAR(40) OUTPUT 9 AS 10 BEGIN 11 -- SET NOCOUNT ON added to prevent extra result sets from 12 -- interfering with SELECT statements. 13 SET NOCOUNT ON; 14 -- Insert statements for procedure here 15 SET @outputV_guid = @Prefix + REPLACE(CAST(NEWID() AS VARCHAR(36)),‘-‘,‘‘) 16 END