标准的long雪花长度为64bit,还要浪费1bit,然后41位时间,10位workid,12位序列

guid长度128位,64位完整的时间tick,32位workid,32位序列,可谓随便用满非常豪华

也就是系统里可以根据需要有的地方存随机guid,有的地方存雪花guid,随便换

随后还有提取时间的方法,由于是64位完整时间,直接拿出来转时间就好了

 

这个类参考别人的代码,如果需要设计更完善的guid雪花,可以在github上或者nuget上找newid这个项目,老外写好的更完善的做法

 

guid长度雪花继承雪花id所有优点和特点,只是长度略长

可以用guid存储,以往习惯guid的人没有压力,对guid支持较好的数据库就能支持好guid雪花,mysql不行

一个项目不同表可以使用不同策略,有的用guid,有的用雪花guid,按需使用,也更方便导数据

时间储存的完整long,可以提取出完整时间,时间照样从0年开始,再老的数据也可以导,只要按时间顺序,自己传个时间给next方法

序列号数量充足,不会动不动就加1秒,workid更长,可以分段放不同的内容

 

using System;
using System.Threading;

namespace Ruifei.Common
{
    public class GuidSnowFlakeGenerator
    {
        readonly uint _c;
        int _a;
        int _b;
        long _lastTick;
        uint _sequence;

        SpinLock _spinLock;

        public GuidSnowFlakeGenerator(uint workId)
        {
            _spinLock = new SpinLock(false);
            _c = workId;
        }


        public Guid Next()
        {
            return Next(DateTime.UtcNow);
        }

        /// <summary>
        /// 仅用于历史数据批量生成Id,必须按时间顺序传入
        /// </summary>
        public Guid Next(DateTime dataTime)
        {
            var ticks = dataTime.ToUniversalTime().Ticks;

            int a;
            int b;
            uint sequence;

            var lockTaken = false;
            try
            {
                _spinLock.Enter(ref lockTaken);

                if (ticks > _lastTick)
                    UpdateTimestamp(ticks);
                else if (_sequence == uint.MaxValue)
                    UpdateTimestamp(_lastTick + 1);

                sequence = _sequence++;

                a = _a;
                b = _b;
            }
            finally
            {
                if (lockTaken)
                    _spinLock.Exit();
            }

            var s = sequence;
            byte[] bytes = new byte[16];
            bytes[0] = (byte)(a >> 24);
            bytes[1] = (byte)(a >> 16);
            bytes[2] = (byte)(a >> 8);
            bytes[3] = (byte)a;
            bytes[4] = (byte)(b >> 24);
            bytes[5] = (byte)(b >> 16);
            bytes[6] = (byte)(b >> 8);
            bytes[7] = (byte)b;
            bytes[8] = (byte)(_c >> 24);
            bytes[9] = (byte)(_c >> 16);
            bytes[10] = (byte)(_c >> 8);
            bytes[11] = (byte)(_c);
            bytes[12] = (byte)(s >> 24);
            bytes[13] = (byte)(s >> 16);
            bytes[14] = (byte)(s >> 8);
            bytes[15] = (byte)(s >> 0);

            return new Guid(bytes);
        }


        void UpdateTimestamp(long tick)
        {
            _b = (int)(tick & 0xFFFFFFFF);
            _a = (int)(tick >> 32);

            _sequence = 0;
            _lastTick = tick;
        }

        public static DateTime GetTime(Guid guid)
        {
            var bytes = guid.ToByteArray();
            long tick = (long)bytes[0] << 56;
            tick += (long)bytes[1] << 48;
            tick += (long)bytes[2] << 40;
            tick += (long)bytes[3] << 32;
            tick += (long)bytes[3] << 24;
            tick += (long)bytes[3] << 16;
            tick += (long)bytes[3] << 8;
            tick += (long)bytes[3];
            return new DateTime(tick, DateTimeKind.Utc);
        }

        public static DateTime GetLocalTime(Guid guid)
        {
            return GetTime(guid);
        }
    }
}

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐