GUID作为数据库主键由于其无序性所以性能不怎么好,SQL Server中有个函数NewSequentialId可以生成有序的GUID,由于在程序中需要用到,就用C#实现了一下,生成的GUID格式基本和SQL Server一致。
程序代码参考了rpcrt4.dll中UuidCreateSequential的实现。
1 public class GuidHelper 2 { 3 private static bool initialised; 4 private static int count; 5 6 private static long time; 7 private static long timelast; 8 private static ushort sequence; 9 10 private static byte[] address; //网卡MAC 11 private static readonly object locker = new object(); 12 public static Guid NewSequentialId() 13 { 14 lock(locker) 15 { 16 if (!initialised) 17 { 18 timelast = UuidGetSystemTime(); 19 count = TICKS_PER_CLOCK_TICK; 20 Random rand = new Random(1); 21 sequence = (ushort)(((rand.Next(1, 32767) & 0xFF) << 8) + rand.Next(1, 32767) & 0xFF); 22 sequence &= 0x1FFF; 23 address = GetAddressBytes(); 24 initialised = true; 25 } 26 while (true) 27 { 28 time = UuidGetSystemTime(); 29 if (time > timelast) 30 { 31 count = 0; 32 break; 33 } 34 if (time < timelast) 35 { 36 sequence = (ushort)((sequence + 1) & 0x1FFF); 37 count = 0; 38 break; 39 } 40 if (count < TICKS_PER_CLOCK_TICK) 41 { 42 count++; 43 break; 44 } 45 } 46 47 timelast = time; 48 time += count; 49 50 byte[] guidArray = new byte[16]; 51 52 uint data1 = (uint)(time & 0xffffffff); 53 ushort data2 = (ushort)((time >> 32) & 0xffff); 54 ushort data3 = (ushort)((time >> 48) & 0x0fff); 55 /* This is a version 1 UUID */ 56 data3 |= (1 << 12); 57 58 guidArray[3] = (byte)data1; 59 guidArray[2] = (byte)(data1 >> 8); 60 guidArray[1] = (byte)(data1 >> 16); 61 guidArray[0] = (byte)(data1 >> 24); 62 guidArray[5] = (byte)data2; 63 guidArray[4] = (byte)(data2 >> 8); 64 guidArray[7] = (byte)data3; 65 guidArray[6] = (byte)(data3 >> 8); 66 guidArray[8] = (byte)(sequence & 0xff); 67 guidArray[9] = (byte)((sequence & 0x3f00) >> 8); 68 guidArray[9] |= 0x80; 69 Array.Copy(address, 0, guidArray, 10, 6); 70 71 return new Guid(guidArray); 72 }//locker 73 }//UuidCreateSequential 74 75 private static readonly int TICKS_PER_CLOCK_TICK = 1000; 76 private static readonly int SECSPERDAY = 86400; 77 private static readonly int TICKSPERSEC = 10000000; 78 private static readonly long SECS_15_OCT_1582_TO_1601 = (17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY; 79 private static readonly long TICKS_15_OCT_1582_TO_1601 = SECS_15_OCT_1582_TO_1601 * TICKSPERSEC; 80 private static long UuidGetSystemTime() 81 { 82 DateTime dt = DateTime.Now; 83 var ft = dt.ToFileTime(); 84 ft += TICKS_15_OCT_1582_TO_1601; 85 return ft; 86 } 87 88 private static byte[] GetAddressBytes() 89 { 90 byte[] bytes; 91 NetworkInterface[] nic = NetworkInterface.GetAllNetworkInterfaces(); 92 if (nic == null || nic.Length < 1) 93 { 94 bytes = new byte[6]; 95 bytes[0] = 0x01; 96 return bytes; 97 } 98 bytes = nic[0].GetPhysicalAddress().GetAddressBytes(); 99 return bytes; 100 } 101 }
代码写的比较粗糙,不过功能已经实现,有需要的朋友可以自行优化!
时间: 2024-11-05 13:43:01