生成唯一值的方法很多,下面就不同环境下生成的唯一标识方法一一介绍,作为工作中的一次总结,有兴趣的可以自行测试:
一、在 .NET 中生成
1、直接用.NET Framework 提供的 Guid() 函数,此种方法使用非常广泛。GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的任何两台计算机都不会生成重复的 GUID 值(即保证所有机器都是唯一的)。关于GUID的介绍在此不作具体熬述,想深入了解可以自行查阅MSDN。代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string _guid = GetGuid(); Console.WriteLine("唯一码:{0}\t长度为:{1}\n去掉连接符:{2}", _guid, _guid.Length, _guid.Replace("-", "")); string uniqueIdString = GuidTo16String(); Console.WriteLine("唯一码:{0}\t长度为:{1}", uniqueIdString, uniqueIdString.Length); long uniqueIdLong = GuidToLongID(); Console.WriteLine("唯一码:{0}\t长度为:{1}", uniqueIdLong, uniqueIdLong.ToString().Length); } /// <summary> /// 由连字符分隔的32位数字 /// </summary> /// <returns></returns> private static string GetGuid() { System.Guid guid = new Guid(); guid = Guid.NewGuid(); return guid.ToString(); } /// <summary> /// 根据GUID获取16位的唯一字符串 /// </summary> /// <param name=\"guid\"></param> /// <returns></returns> public static string GuidTo16String() { long i = 1; foreach (byte b in Guid.NewGuid().ToByteArray()) i *= ((int)b + 1); return string.Format("{0:x}", i - DateTime.Now.Ticks); } /// <summary> /// 根据GUID获取19位的唯一数字序列 /// </summary> /// <returns></returns> public static long GuidToLongID() { byte[] buffer = Guid.NewGuid().ToByteArray(); return BitConverter.ToInt64(buffer, 0); } } }
2、用 DateTime.Now.ToString("yyyyMMddHHmmssms") 和 .NET Framework 提供的 RNGCryptoServiceProvider() 结合生成,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string uniqueNum = GenerateOrderNumber(); Console.WriteLine("唯一码:{0}\t 长度为:{1}", uniqueNum, uniqueNum.Length); //测试是否会生成重复 Console.WriteLine("时间+RNGCryptoServiceProvider()结合生成的唯一值,如下:"); string _tempNum = string.Empty; for (int i = 0; i < 1000; i++) { string uNum = GenerateOrderNumber(); Console.WriteLine(uNum); if (string.Equals(uNum, _tempNum)) { Console.WriteLine("上值存在重复,按Enter键继续"); Console.ReadKey(); } //Sleep当前线程,是为了延时,从而不产生重复值。可以把它注释掉测试看 Thread.Sleep(300); _tempNum = uNum; } } /// <summary> /// 唯一订单号生成 /// </summary> /// <returns></returns> public static string GenerateOrderNumber() { string strDateTimeNumber = DateTime.Now.ToString("yyyyMMddHHmmssms"); string strRandomResult = NextRandom(1000, 1).ToString(); return strDateTimeNumber + strRandomResult; } /// <summary> /// 参考:msdn上的RNGCryptoServiceProvider例子 /// </summary> /// <param name="numSeeds"></param> /// <param name="length"></param> /// <returns></returns> private static int NextRandom(int numSeeds, int length) { // Create a byte array to hold the random value. byte[] randomNumber = new byte[length]; // Create a new instance of the RNGCryptoServiceProvider. System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); // Fill the array with a random value. rng.GetBytes(randomNumber); // Convert the byte to an uint value to make the modulus operation easier. uint randomResult = 0x0; for (int i = 0; i < length; i++) { randomResult |= ((uint)randomNumber[i] << ((length - 1 - i) * 8)); } return (int)(randomResult % numSeeds) + 1; } } }
3、用 [0-9A-Z] + Guid.NewGuid() 结合生成特定位数的唯一字符串,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string uniqueText = GenerateUniqueText(8); Console.WriteLine("唯一码:{0}\t 长度为:{1}", uniqueText, uniqueText.Length); //测试是否会生成重复 Console.WriteLine("由[0-9A-Z] + NewGuid() 结合生成的唯一值,如下:"); IList<string> list = new List<string>(); for (int i = 1; i <= 1000; i++) { string _uT = GenerateUniqueText(8); Console.WriteLine("{0}\t{1}", list.Count, _uT); if (list.Contains(_uT)) { Console.WriteLine("{0}值存在重复", _uT); Console.ReadKey(); } list.Add(_uT); //if (i % 200 == 0) //{ //Console.WriteLine("没有重复,按Enter键往下看"); //Console.ReadKey(); //} } list.Clear(); } /// <summary> /// 生成特定位数的唯一字符串 /// </summary> /// <param name="num">特定位数</param> /// <returns></returns> public static string GenerateUniqueText(int num) { string randomResult = string.Empty; string readyStr = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char[] rtn = new char[num]; Guid gid = Guid.NewGuid(); var ba = gid.ToByteArray(); for (var i = 0; i < num; i++) { rtn[i] = readyStr[((ba[i] + ba[num + i]) % 35)]; } foreach (char r in rtn) { randomResult += r; } return randomResult; } } }
4、用单例模式实现,由[0-9a-z]组合生成的唯一值,此文不讨论单例模式的多种实现方式与性能问题,随便弄一种方式实现,代码如下:
Demo结构如图:
Program.cs 程序:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Xml; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { CreateID createID = CreateID.GetInstance(); //测试是否会生成重复 Console.WriteLine("单例模式实现,由[0-9a-z]组合生成的唯一值,如下:"); IList<string> list = new List<string>(); for (int i = 1; i <= 1000000000; i++) { string strUniqueNum = createID.CreateUniqueID(); Console.WriteLine("{0}\t{1}", list.Count, strUniqueNum); if (list.Contains(strUniqueNum)) { Console.WriteLine("{0}值存在重复", strUniqueNum); Console.ReadKey(); } list.Add(strUniqueNum); if (i % 200 == 0) { Console.WriteLine("没有重复,按Enter键往下看"); Console.ReadKey(); } } list.Clear(); } } /// <summary> /// 单例模式实现 /// 唯一值由[0-9a-z]组合而成,且生成的每个ID不能重复 /// </summary> public class CreateID { private static CreateID _instance; private static readonly object syncRoot = new object(); private EHashtable hashtable = new EHashtable(); private string _strXMLURL = string.Empty; private CreateID() { hashtable.Add("0", "0"); hashtable.Add("1", "1"); hashtable.Add("2", "2"); hashtable.Add("3", "3"); hashtable.Add("4", "4"); hashtable.Add("5", "5"); hashtable.Add("6", "6"); hashtable.Add("7", "7"); hashtable.Add("8", "8"); hashtable.Add("9", "9"); hashtable.Add("10", "a"); hashtable.Add("11", "b"); hashtable.Add("12", "c"); hashtable.Add("13", "d"); hashtable.Add("14", "e"); hashtable.Add("15", "f"); hashtable.Add("16", "g"); hashtable.Add("17", "h"); hashtable.Add("18", "i"); hashtable.Add("19", "j"); hashtable.Add("20", "k"); hashtable.Add("21", "l"); hashtable.Add("22", "m"); hashtable.Add("23", "n"); hashtable.Add("24", "o"); hashtable.Add("25", "p"); hashtable.Add("26", "q"); hashtable.Add("27", "r"); hashtable.Add("28", "s"); hashtable.Add("29", "t"); hashtable.Add("30", "u"); hashtable.Add("31", "v"); hashtable.Add("32", "w"); hashtable.Add("33", "x"); hashtable.Add("34", "y"); hashtable.Add("35", "z"); _strXMLURL = System.IO.Path.GetFullPath(@"..\..\") + "XMLs\\record.xml"; } public static CreateID GetInstance() { if (_instance == null) { lock (syncRoot) { if (_instance == null) { _instance = new CreateID(); } } } return _instance; } /// <summary> /// 创建UniqueID /// </summary> /// <returns>UniqueID</returns> public string CreateUniqueID() { long _uniqueid = GetGuidFromXml(); return Convert10To36(_uniqueid); } /// <summary> /// 获取UniqueID总记录,即获取得到的这个ID是第几个ID /// 更新UniqueID使用的个数,用于下次使用 /// </summary> /// <returns></returns> private long GetGuidFromXml() { long record = 0; XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(_strXMLURL); XmlElement rootNode = xmldoc.DocumentElement; //此次的个数值 record = Convert.ToInt64(rootNode["record"].InnerText); //此次的个数值+1 == 下次的个数值 rootNode["record"].InnerText = Convert.ToString(record + 1); xmldoc.Save(_strXMLURL); return record; } /// <summary> /// 10进制转36进制 /// </summary> /// <param name="intNum10">10进制数</param> /// <returns></returns> private string Convert10To36(long intNum10) { string strNum36 = string.Empty; long result = intNum10 / 36; long remain = intNum10 % 36; if (hashtable.ContainsKey(remain.ToString())) strNum36 = hashtable[remain.ToString()].ToString() + strNum36; intNum10 = result; while (intNum10 / 36 != 0) { result = intNum10 / 36; remain = intNum10 % 36; if (hashtable.ContainsKey(remain.ToString())) strNum36 = hashtable[remain.ToString()].ToString() + strNum36; intNum10 = result; } if (intNum10 > 0 && intNum10 < 36) { if (hashtable.ContainsKey(intNum10.ToString())) strNum36 = hashtable[intNum10.ToString()].ToString() + strNum36; } return strNum36; } } /// <summary> /// Summary description for EHashTable /// </summary> public class EHashtable : Hashtable { private ArrayList list = new ArrayList(); public override void Add(object key, object value) { base.Add(key, value); list.Add(key); } public override void Clear() { base.Clear(); list.Clear(); } public override void Remove(object key) { base.Remove(key); list.Remove(key); } public override ICollection Keys { get { return list; } } } }
XML:
<?xml version="1.0" encoding="utf-8"?> <root> <record id="record">1</record> </root>
二、在JS中生成GUID,类似.NET中的 Guid.NewGuid(),代码如下:
function newGuid() { //方法一: var guid = ""; var n = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); for (var i = 1; i <= 8; i++) { guid += n; } return guid; } function newGuid() { //方法二: var guid = ""; for (var i = 1; i <= 32; i++) { var n = Math.floor(Math.random() * 16.0).toString(16); guid += n; if ((i == 8) || (i == 12) || (i == 16) || (i == 20)) guid += "-"; } return guid; }
三、在SQL存储过程生成GUID,代码如下:
-- ============================================= -- Author: JBen -- Create date: 2012-06-05 -- Description: 生成唯一标识ID,公共存储过程,可设置在别的存储过程调用此存储过程传不同的前缀 -- ============================================= ALTER PROCEDURE [dbo].[pro_CreateGuid] @Prefix NVARCHAR(10), @outputV_guid NVARCHAR(40) OUTPUT AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure here SET @outputV_guid = @Prefix + REPLACE(CAST(NEWID() AS VARCHAR(36)),'-','') END