从Redis生成数据表主键标识
对于MySql的全局ID(主键),我们一般采用自增整数列、程序生成GUID、单独的表作为ID生成器,这几种方案各有优劣,最终效率都不能说十分理想(尤其海量数据下),其实通过Redis的INCR可以很方便生成自增数,因为是操作缓存,生成的效率也不错。
插入数据库的主键也是连续增长的,配合索引,读取效率也很高。
下面是从Redis中获取新的自增数的代码:
public sealed class Utils
{
private static readonly object sequence_locker = new object(); /// <summary>
/// 从Redis获取一个自增序列标识
/// </summary>
/// <param name="key">键名</param>
/// <param name="getting">获取序列标识替代生成方法(若缓存中不存在)</param>
public static int NewSequenceFromRedis(string key, Func<int> alternative)
{
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException("key");
lock (sequence_locker)
{
RedisHelper redis = new RedisHelper(); //in db1
long value = redis.StringIncrement(key, );
if (value > Int32.MaxValue || value < Int32.MinValue) throw new OverflowException("The sequence overflow.");
if (value <= && alternative != null)
{
value = alternative();
redis.StringSet(key, value.ToString()); //update
} return (int)value;
}
}
}
我的项目用的Repository模式,所以获取新主键的方法我写到Repository父类中(在接口IRepository中有定义),这样各个Repository可以重载属性TableName,当然你完全可以把NewIdentity独立出去作为公共方法,只要传入TableName即可
public abstract class RepositoryBase : IRepository
{
protected IDbConnection _db;
public RepositoryBase(IDbConnection connection)
{
_db = connection;
} protected virtual string TableName { get; } public virtual int NewIdentity()
{
if (string.IsNullOrEmpty(this.TableName))
throw new NoNullAllowedException("TableName is null."); var redisKey = $"Sequence_{TableName}.Id"; //eg. Sequence_lottery.Id, Sequence_player.Id
var id = Utils.NewSequenceFromRedis(redisKey, () =>
{
//如果从Redis中没获取到主键标识(比如Redis键被删除),则用数据表最大标识+1替代
return _db.ExecuteScalar<int>("SELECT MAX(id) AS MaxId FROM " + TableName) + 1;
});
return id;
}
}
下面是测试代码,并且用StopWatch测试每次执行效率:
using (var ctx = DI.Resolve<IRepositoryContext>())
{
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
var userId = ctx.Resolve<IUserRepository>().NewIdentity();
sw.Stop();
Console.WriteLine("userId={0}, elapsed: {1}ms", userId, sw.ElapsedMilliseconds); sw.Restart();
var gameId = ctx.Resolve<IGameRepository>().NewIdentity();
sw.Stop();
Console.WriteLine("gameId={0}, elapsed: {1}ms", gameId, sw.ElapsedMilliseconds); sw.Restart();
var roomId = ctx.Resolve<IGameRepository>().NewRoomIdentity();
sw.Stop();
Console.WriteLine("roomId={0}, elapsed: {1}ms", roomId, sw.ElapsedMilliseconds); sw.Restart();
var betItemId = ctx.Resolve<IGameRepository>().NewBetItemIdentity();
sw.Stop();
Console.WriteLine("betItemId={0}, elapsed: {1}ms", betItemId, sw.ElapsedMilliseconds); sw.Restart();
var lotteryId = ctx.Resolve<ILotteryRepository>().NewIdentity();
sw.Stop();
Console.WriteLine("lotteryId={0}, elapsed: {1}ms", lotteryId, sw.ElapsedMilliseconds); //省略的代码。。。
}
运行结果如下,除第一次获取主键开销98毫秒(估计建立redis连接有关),后面的几乎都是0毫秒(Redis本来就飞快,这里不用考虑数据库连接开闭的时间消耗)

查看Redis中的键值:

当然,代码还需要完善,比如Redis挂了的情况,ID主键可以读取MAX(ID)+1来替代主键生成,但是Redis又恢复后,自增数怎么同步
从Redis生成数据表主键标识的更多相关文章
- 设置MySQL数据表主键
设置MySQL数据表主键: 使用“primary key”关键字创建主键数据列.被设置为主键列不允许出现重复的值,很多情况下与“auto_increment”递增数字相结合.如下SQL语句所示: My ...
- 使用GUID作为数据表主键的好处(转)
http://blog.itpub.net/3875/viewspace-789520/ 分类: 数据库开发技术 使用GUID作为数据表主键的好处 [@more@] 使用GUID作为数据表主键的好处 ...
- SQLITE数据表主键设置Id自增方法
SQLITE数据表主键设置Id自增方法 标签: sqliteintegerinsertnulltableapi 2010-01-12 08:39 35135人阅读 评论(8) 收藏 举报 分类: S ...
- django学习-13.通过pk值手动设置数据表主键
1.前言 通过django框架的Model层来新增数据库表时,如果在需要新增的表字段里任何一个表字段都没设置主键,框架会默认新增一个表字段id并把该表字段id设置为主键. 那么,如果我们想自己动手设置 ...
- Mybatis框架(9)---Mybatis自定义插件生成雪花ID做为表主键项目
Mybatis自定义插件生成雪花ID做为主键项目 先附上项目项目GitHub地址 spring-boot-mybatis-interceptor 有关Mybatis雪花ID主键插件前面写了两篇博客作为 ...
- MyBatis框架——mybatis插入数据返回主键(mysql、oracle)
向数据库中插入数据时,大多数情况都会使用自增列或者UUID做为主键.主键的值都是插入之前无法知道的,但很多情况下我们在插入数据后需要使用刚刚插入数据的主键,比如向两张关联表A.B中插入数据(A的主键是 ...
- 解决getJdbcTemplate往oracle数据库中插入数据返回主键出错问题
我们使用Spring中的JdbcDaoSupport往Mysql中插入数据并返回主键代码,我们使用的mysql数据库,主键在数据库中设置为自增长:该类继承自JdbcDaoSupport,所以能直接使用 ...
- [Done]SnowFlake生成Long类型主键返回前台过长导致精度缺失的问题
问题描述: 在开发过程中,项目的主键生成器是SnowFlake,其生成的long主键是28位, 但是js中Long的最大值:https://blog.csdn.net/sunmerZeal/artic ...
- 如何准确高效的获取数据库新插入数据的主键id
例如我们新建了一张表UserInformation,字段如下Id,为主键,自增,其它字段Name,Pwd,Email 然后我们来执行一个新增插入操作: insert into UserInformat ...
随机推荐
- python学习Day1 计算机原理编程思维
一.学习思想:3W+1H 学什么(what).为什么学(why).用在哪里(where).怎么用(how) 学习编程语言重在代码量.代码量.代码量! 二.计算机五大组成部分,三大核心: 五大组成部 ...
- 爬虫 1 requests 、beautifulsoup
1.requests 1.method 提交方式:post.get.put.delete.options.head.patch 2.url 访问地址 3.params 在url中传递的参数,GET p ...
- mysql linux安装
Mysql(使用版本5.7.25) 1. 检查是否已安装 #rpm -qa|grep -i mysql 2. 下载安装包 网址:https://dev.mysql.com/downloads/my ...
- python的条件语句
Python程序语言指定任何非0和非空(null)值为true,0 或者 null为false. Python 编程中 if 语句用于控制程序的执行,基本形式为: if 判断条件: 执行语句…… el ...
- python3 urllib.parse 常用函数
1.获取url参数 urlparse from urllib import parse url = "https://docs.python.org/3.5/library/urllib.p ...
- 定义java中的变量
四种类型 1.整数 2.小数 3.字符 4.布尔值 八种 整数(byte 字节1 范围-128~127 ) (short 字节 2) (int 字节4) (lon ...
- 杨其菊201771010134《面向对象程序设计(java)》第一周学习总结
第一部分:课程准备部分 填写课程学习 平台注册账号, 平台名称 注册账号 博客园:www.cnblogs.com 安迪儿 程序设计评测:https://pintia.cn/ 迷路的麋鹿回不来家了 代码 ...
- 记一次Java Core Dump分析过程
#背景提要 很久没有亲自动手部署代码了,命令行的亲切感越来越低.放飞了键盘,习惯了鼠标操作的windows环境.冷不丁实操部署也是不错的. 常常在部署时,运维同学对于[hs_err_pid]文件视而不 ...
- python 常用知识点
1,字典get用法 如果key没有值,返回一个None >>> dic = {'k1':'v1','k2':'v2','k3':'v3'} >>> dic.get( ...
- Python12/25--前端之BOM/DOM
一.DOM 1. 什么是DOM 文档对象模型 Document Object Model 文档对象模型 是表示和操作 HTML和XML文档内容的基础API 文档对象模型,是W3C组织推荐的处理可扩展标 ...