当前位置:  开发笔记 > 编程语言 > 正文

顺序Guid发生器

如何解决《顺序Guid发生器》经验,为你挑选了4个好方法。

有没有办法获得Sql Server 2005+ Sequential Guid生成器的功能,而无需插入记录来回读往返或调用本机win dll调用?我看到有人回答使用rpcrt4.dll,但我不确定是否可以从我的托管环境中进行生产.

编辑:使用@John Boker的答案我试图把它变成GuidComb生成器的更多,而不是依赖于最后生成的Guid而不是重新开始.对于种子,而不是从我使用的Guid.Empty开始

public SequentialGuid()
{
    var tempGuid = Guid.NewGuid();
    var bytes = tempGuid.ToByteArray();
    var time = DateTime.Now;
    bytes[3] = (byte) time.Year;
    bytes[2] = (byte) time.Month;
    bytes[1] = (byte) time.Day;
    bytes[0] = (byte) time.Hour;
    bytes[5] = (byte) time.Minute;
    bytes[4] = (byte) time.Second;
    CurrentGuid = new Guid(bytes);
}

我根据评论做了这个

// 3 - the least significant byte in Guid ByteArray 
        [for SQL Server ORDER BY clause]
// 10 - the most significant byte in Guid ByteArray 
        [for SQL Server ORDERY BY clause]
SqlOrderMap = new[] {3, 2, 1, 0, 5, 4, 7, 6, 9, 8, 15, 14, 13, 12, 11, 10};

这看起来像我想用DateTime为guid播种的方式,还是看起来我应该反过来并从SqlOrderMap索引的末尾开始向后工作?我不太关心他们是否会在创建初始guid时进行分页,因为它只会在应用程序回收期间发生.



1> Ian Boyd..:

您可以使用SQL Server使用的相同Win32 API函数:

UuidCreateSequential

并应用一些位移以将值放入big-endian顺序.

因为你想在C#中使用它:

private class NativeMethods
{
   [DllImport("rpcrt4.dll", SetLastError=true)]
   public static extern int UuidCreateSequential(out Guid guid);
}

public static Guid NewSequentialID()
{
   //Code is released into the public domain; no attribution required
   const int RPC_S_OK = 0;

   Guid guid;
   int result = NativeMethods.UuidCreateSequential(out guid);
   if (result != RPC_S_OK)
      return Guid.NewGuid();

   //Endian swap the UInt32, UInt16, and UInt16 into the big-endian order (RFC specified order) that SQL Server expects
   //See /sf/ask/17360801/
   //Short version: UuidCreateSequential writes out three numbers in litte, rather than big, endian order
   var s = guid.ToByteArray();
   var t = new byte[16];

   //Endian swap UInt32
   t[3] = s[0];
   t[2] = s[1];
   t[1] = s[2];
   t[0] = s[3];
   //Endian swap UInt16
   t[5] = s[4];
   t[4] = s[5];
   //Endian swap UInt16
   t[7] = s[6];
   t[6] = s[7];
   //The rest are already in the proper order
   t[8] = s[8];
   t[9] = s[9];
   t[10] = s[10];
   t[11] = s[11];
   t[12] = s[12];
   t[13] = s[13];
   t[14] = s[14];
   t[15] = s[15];

   return new Guid(t);
}

也可以看看

是否有与SQL Server相同的.NET newsequentialid()


微软UuidCreateSequential只是一个类型1 uuid 的实现RFC 4122.

一个uuid有三个重要部分:

node:(6个字节) - 计算机的MAC地址

timestamp:(7字节) - 自1582年10月15日00:00:00.00(格里高利改革为基督教历法的日期)以来的100 ns间隔数

clockSequenceNumber (2个字节) - 计数器,以防你生成一个超过100ns的guid,或者你改变你的mac地址

基本算法是:

    获得系统范围的锁定

    读取最后一个node,timestampclockSequenceNumber从持久存储(注册表/文件)

    获取当前node(即MAC地址)

    得到当前 timestamp

    a)如果保存的状态不可用或已损坏,或者mac地址已更改,则生成随机 clockSequenceNumber

    b)如果状态可用,但当前timestamp与保存的时间戳相同或更旧,则递增clockSequenceNumber

    保存node,timestampclockSequenceNumber返回持久存储

    释放全局锁

    根据rfc格式化guid结构

有一个4位版本号,2位变量也需要与数据进行AND运算:

guid = new Guid(
      timestamp & 0xFFFFFFFF,  //timestamp low
      (timestamp >> 32) & 0xFFFF, //timestamp mid
      ((timestamp >> 40) & 0x0FFF), | (1 << 12) //timestamp high and version (version 1)
      (clockSequenceNumber & 0x3F) | (0x80), //clock sequence number and reserved
      node[0], node[1], node[2], node[3], node[4], node[5], node[6]);

注意:完全未经测试; 我只是从RFC中看到它.

可能必须更改字节顺序(这是sql server的字节顺序)

您可能想要创建自己的版本,例如版本6(版本1-5已定义).这样你就可以保证普遍独特



2> John Boker..:

这个人想出了一些东西来制作顺序guids,这是一个链接

http://developmenttips.blogspot.com/2008/03/generate-sequential-guids-for-sql.html

相关代码:

public class SequentialGuid {
    Guid _CurrentGuid;
    public Guid CurrentGuid {
        get {
            return _CurrentGuid;
        }
    }

    public SequentialGuid() {
        _CurrentGuid = Guid.NewGuid();
    }

    public SequentialGuid(Guid previousGuid) {
        _CurrentGuid = previousGuid;
    }

    public static SequentialGuid operator++(SequentialGuid sequentialGuid) {
        byte[] bytes = sequentialGuid._CurrentGuid.ToByteArray();
        for (int mapIndex = 0; mapIndex < 16; mapIndex++) {
            int bytesIndex = SqlOrderMap[mapIndex];
            bytes[bytesIndex]++;
            if (bytes[bytesIndex] != 0) {
                break; // No need to increment more significant bytes
            }
        }
        sequentialGuid._CurrentGuid = new Guid(bytes);
        return sequentialGuid;
    }

    private static int[] _SqlOrderMap = null;
    private static int[] SqlOrderMap {
        get {
            if (_SqlOrderMap == null) {
                _SqlOrderMap = new int[16] {
                    3, 2, 1, 0, 5, 4, 7, 6, 9, 8, 15, 14, 13, 12, 11, 10
                };
                // 3 - the least significant byte in Guid ByteArray [for SQL Server ORDER BY clause]
                // 10 - the most significant byte in Guid ByteArray [for SQL Server ORDERY BY clause]
            }
            return _SqlOrderMap;
        }
    }
}



3> Moslem Ben D..:

以下是NHibernate如何实现Guid.Comb算法:

private 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);
}



4> Alex Siepman..:

可以在此处找到经常更新(每毫秒至少3次)的顺序指南.它是使用常规C#代码创建的(没有本机代码调用).


没有nuget包然后:)
推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有