在 NHibernate 中使用 Snow Flake ID
时间:2022-07-22
本文章向大家介绍在 NHibernate 中使用 Snow Flake ID,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Snow Flake ID 算法简介
Snow Flake 是 Twitter 开源的分布式 ID 生成算法,结果是一个 long 型的 ID。其核心思想是:
- 使用 41bit 作为毫秒时间戳;
- 10bit 作为机器的 ID ( 5 个 bit 是数据中心,5 个 bit 的机器 ID );
- 12bit 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID );
- 最后还有一个符号位,永远是 0 。
如下图所示:
Snow Flake ID 算法的优点是:
- 所有生成的 id 按时间趋势递增(时间戳), 方便排序;
- 整个系统内不会产生重复 id (因为有 datacenterId 和 workerId 来做区分)。
- 结果是一个长整型数字 (int64) , 索引性能也比较好。
关于 Snow Flake ID 算法, 网上已经有太多的介绍, 因此不再做过多的描述。
数据库实现
关于 Snow Flake ID 算法的实现, 已经有多种语言版本的实现, 这里以 PostgreSQL 为例, 使用 sql 实现个简化版。
先创建一个序列, 生成毫秒内的流水号, sql 语句如下:
CREATE SEQUENCE public.snow_flake_id_seq;
ALTER SEQUENCE public.snow_flake_id_seq
OWNER TO postgres;
再创建一个函数, 实现 Snow Flake ID 算法, sql 语句如下:
CREATE OR REPLACE FUNCTION public.snow_flake_id()
RETURNS bigint
LANGUAGE 'sql'
COST 100
VOLATILE
AS $BODY$
SELECT (EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000)::bigint * 1000000 -- 将时间戳(精确到毫秒)放在最高位, 便于排序
+ 5 * 10000 -- 数据库实例 id , 可以根据数据库进行修改
+ nextval('public.snow_flake_id_seq') % 1000 -- 毫秒内的序列号, 求 1000 的余数, 保证在 0 ~ 999 的范围内
as snow_flake_id
$BODY$;
ALTER FUNCTION public.snow_flake_id()
OWNER TO postgres;
COMMENT ON FUNCTION public.snow_flake_id()
IS 'snow flake id ';
测试生成的 ID , 执行 sql 语句 select public.snow_flake_id()
可以得到下面的结果:
1534042025838050074
说明如下:
- 1534042025838 为 Unix 时间戳, 精确到毫秒
- 050 为数据库实例
- 074 为毫秒内的流水号
因此, 这个结果基本上符合 Snow Flake ID 算法。
在数据库使用这个 ID 也很容容易, 只要设置数据表的对应的列的默认值即可, 示例如下:
CREATE TABLE public.snow_flake_test
(
id bigint NOT NULL DEFAULT public.snow_flake_id(), -- 设置 ID 列的默认值, 自动生成 Snow Flake ID
name character varying(32) COLLATE pg_catalog."default",
CONSTRAINT snow_flake_test_pkey PRIMARY KEY (id)
)
现在执行插入语句
insert into public.snow_flake_test (name)
values ('snow flake id test')
数据库的到的结果为
id bigint |
name character varying(32) |
---|---|
1534042851390050075 |
snow flake id test |
NHibernate 配置
为了能够在 NHibernate 中使用, 需要根据上面的 snow_flake_test
表创建一个实体类, 代码如下:
public class SnowFlakeTestEntity {
public virtual long Id { get; set; }
public virtual string Name { get; set; }
}
Id 是在数据库生成的, 所以应该使用的生成器为 trigger-identity
, 对应的 xml 映射文件为如下:
<class name="SnowFlakeTestEntity" table="snow_flake_test" schema="public">
<id name="Id" column="id" type="long">
<generator class="trigger-identity">
</generator>
</id>
<property name="Name" column="name" type="string" length="32" />
</class>
最后, 写一个单元测试来验证一下配置, 代码如下:
[Fact]
public void _02_CanInsertSnowFlakeId() {
using (var session = factory.OpenSession()) {
var entity = new SnowFlakeTestEntity {
Name = "snow flake id test"
};
session.Save(entity);
Assert.True(entity.Id > 0);
Console.WriteLine($"Id: {entity.Id}");
}
}
运行测试代码, 可以得到如下的输出:
Starting test execution, please wait...[xUnit.net 00:00:01.19]
NHibernate:
INSERT
INTO
public.snow_flake_test
(name)
VALUES
(:p0) returning id;
:p0 = 'd0f7198ea8ab4faa982a16df7cc8e96b' [Type: String (0:0:0)], :nhIdOutParam = NULL [Type: Int64 (0:0:0)]
Id: 1534043843651050079
Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 4.5339 Seconds
毫无悬念, 单元测试通过, 可以在 NHibernate 中愉快的使用 Snow Flake ID 了。
- LINQ驱动数据的查询功能
- JS魔法堂:jQuery.Deferred(jQuery1.5-2.1)源码剖析
- 一步一步学习Bootstrap系列--表单布局
- Java进阶01 String类
- linux(十二)之用户管理
- Dapper.Net 应用
- linux(十)配置ssh免密登录实现
- 微信群也有群相册功能了,终于可以给手机相册腾出空间了!
- PHP5.3、PHP5.4安装ZendOptimizer
- linux(十一)之初始化文件
- C编译: 动态连接库 (.so文件)
- 腾讯叮当首都发布生态合作伙伴计划,全面开放AI能力
- Python火爆的背后的应用领域是数据挖掘、大数据和人工智能的应用吗?
- linux(九)之网络基础
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法