对于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生成数据表主键标识的更多相关文章

  1. 设置MySQL数据表主键

    设置MySQL数据表主键: 使用“primary key”关键字创建主键数据列.被设置为主键列不允许出现重复的值,很多情况下与“auto_increment”递增数字相结合.如下SQL语句所示: My ...

  2. 使用GUID作为数据表主键的好处(转)

    http://blog.itpub.net/3875/viewspace-789520/ 分类: 数据库开发技术 使用GUID作为数据表主键的好处 [@more@] 使用GUID作为数据表主键的好处 ...

  3. SQLITE数据表主键设置Id自增方法

    SQLITE数据表主键设置Id自增方法 标签: sqliteintegerinsertnulltableapi 2010-01-12 08:39 35135人阅读 评论(8) 收藏 举报  分类: S ...

  4. django学习-13.通过pk值手动设置数据表主键

    1.前言 通过django框架的Model层来新增数据库表时,如果在需要新增的表字段里任何一个表字段都没设置主键,框架会默认新增一个表字段id并把该表字段id设置为主键. 那么,如果我们想自己动手设置 ...

  5. Mybatis框架(9)---Mybatis自定义插件生成雪花ID做为表主键项目

    Mybatis自定义插件生成雪花ID做为主键项目 先附上项目项目GitHub地址 spring-boot-mybatis-interceptor 有关Mybatis雪花ID主键插件前面写了两篇博客作为 ...

  6. MyBatis框架——mybatis插入数据返回主键(mysql、oracle)

    向数据库中插入数据时,大多数情况都会使用自增列或者UUID做为主键.主键的值都是插入之前无法知道的,但很多情况下我们在插入数据后需要使用刚刚插入数据的主键,比如向两张关联表A.B中插入数据(A的主键是 ...

  7. 解决getJdbcTemplate往oracle数据库中插入数据返回主键出错问题

    我们使用Spring中的JdbcDaoSupport往Mysql中插入数据并返回主键代码,我们使用的mysql数据库,主键在数据库中设置为自增长:该类继承自JdbcDaoSupport,所以能直接使用 ...

  8. [Done]SnowFlake生成Long类型主键返回前台过长导致精度缺失的问题

    问题描述: 在开发过程中,项目的主键生成器是SnowFlake,其生成的long主键是28位, 但是js中Long的最大值:https://blog.csdn.net/sunmerZeal/artic ...

  9. 如何准确高效的获取数据库新插入数据的主键id

    例如我们新建了一张表UserInformation,字段如下Id,为主键,自增,其它字段Name,Pwd,Email 然后我们来执行一个新增插入操作: insert into UserInformat ...

随机推荐

  1. cdnbest架设cdn同一个源用不同的端口访问如何设置

    在站点里的应用防火墙-->高级设置里配置 比如test.com要同时用80和88访问

  2. CentOS7使用ZFS文件系统

    默认情况下,CentOS7并没有含ZFS支持的文件和,需要进行更新和安装第三方库. Step 1:安装第三方库和更新系统 [root@localhost ~]# rpm -Uvh http://www ...

  3. Solidity合约间的调用-1

    当调用其它合约的函数时,可以通过选项.value(),和.gas()来分别指定,要发送的ether量(以wei为单位),和gas值. pragma solidity ^; contract InfoF ...

  4. EF ++属性会更新实体

    var lastBaby = await _babyRepository.FirstOrDefaultAsync(); ++lastBaby.sort; -- sort原本为1 -- 最终会生成一条语 ...

  5. python爬虫之urllib

    #coding=utf-8 #urllib操作类 import time import urllib.request import urllib.parse from urllib.error imp ...

  6. 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 ...

  7. AutoCAD开发1---获取块属性

    Private Sub CommandButton1_Click() Dim pEntity As AcadObject Dim pBlock As AcadBlockReference Dim pP ...

  8. windows 性能监视器常用计数器

    转载地址:https://www.jianshu.com/p/f4406c29542a?utm_campaign=maleskine&utm_content=note&utm_medi ...

  9. Android 软件退出系统方法重写

    Android 软件退出系统按键方法重写 //针对Andriod软件退出系统按键方法重写 ;//key down time @Override public boolean onKeyDown(int ...

  10. 连接hive

    bin/hiveserver2 nohup bin/hiveserver2 1>/var/log/hiveserver.log 2>/var/log/hiveserver.err & ...