从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 ...
随机推荐
- cdnbest架设cdn同一个源用不同的端口访问如何设置
在站点里的应用防火墙-->高级设置里配置 比如test.com要同时用80和88访问
- CentOS7使用ZFS文件系统
默认情况下,CentOS7并没有含ZFS支持的文件和,需要进行更新和安装第三方库. Step 1:安装第三方库和更新系统 [root@localhost ~]# rpm -Uvh http://www ...
- Solidity合约间的调用-1
当调用其它合约的函数时,可以通过选项.value(),和.gas()来分别指定,要发送的ether量(以wei为单位),和gas值. pragma solidity ^; contract InfoF ...
- EF ++属性会更新实体
var lastBaby = await _babyRepository.FirstOrDefaultAsync(); ++lastBaby.sort; -- sort原本为1 -- 最终会生成一条语 ...
- python爬虫之urllib
#coding=utf-8 #urllib操作类 import time import urllib.request import urllib.parse from urllib.error imp ...
- Codeforces Round #436 (Div. 2)C. Bus 模拟
C. Bus time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard input out ...
- AutoCAD开发1---获取块属性
Private Sub CommandButton1_Click() Dim pEntity As AcadObject Dim pBlock As AcadBlockReference Dim pP ...
- windows 性能监视器常用计数器
转载地址:https://www.jianshu.com/p/f4406c29542a?utm_campaign=maleskine&utm_content=note&utm_medi ...
- Android 软件退出系统方法重写
Android 软件退出系统按键方法重写 //针对Andriod软件退出系统按键方法重写 ;//key down time @Override public boolean onKeyDown(int ...
- 连接hive
bin/hiveserver2 nohup bin/hiveserver2 1>/var/log/hiveserver.log 2>/var/log/hiveserver.err & ...