首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分布式自增数据库ID

分布式自增数据库ID

作者头像
陌无崖
发布2020-07-27 14:42:35
1.5K0
发布2020-07-27 14:42:35
举报

作者 | 陌无崖

转载请联系授权

引言

今天在写项目的时候学习了一个用代码编写的自增的数据库ID,其实是一个ID缓冲池。使用了golang中chan类型。

建表

我们希望该ID缓冲池可以为我们其他不同的数据表进行ID的生成,因此需要建一个如下表:

CREATE TABLE `uid` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `business_id` varchar(128) COLLATE utf8mb4_bin NOT NULL COMMENT '业务id',
  `max_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '最大id',
  `step` int(10) unsigned NOT NULL DEFAULT '1000' COMMENT '步长',
  `description` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '描述',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_business_id` (`business_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='分布式自增主键';

-- ----------------------------
-- Records of uid
-- ----------------------------
INSERT INTO `uid` VALUES ('1', 'device_id', '1689', '10', '设备id', '2019-10-15 16:42:05', '2020-02-05 06:57:29');
INSERT INTO `uid` VALUES ('2', 'test', '20', '10', '测试', '2020-02-05 06:59:44', '2020-02-05 07:05:12');

代码思路

定义结构体绑定sql
type Uid struct {
    db         *sql.DB
    businessId string
    ch         chan int64//缓冲池的大小
    min, max   int64
}
新建一个UID
// 新建一个Uid并一直生产ID
func NewUid(db *sql.DB, businessId string, len int) (*Uid, error) {
    lid := Uid{
        db:         db,
        businessId: businessId,
        ch:         make(chan int64, len),
    }
    go lid.produceId()
    return &lid, nil
}
生产ID
  • 首先从数据库中加载获得当前数据的最大值
  • 循环生成自增ID
func (u *Uid) produceId() {
    // 从数据库中获取id
    u.reload()

    for {
        if u.min >= u.max {
            // 从数据库中获取id
            u.reload()
        }
        u.min++
        u.ch <- u.min
    }
}

在上述代码中当ch中达到了最大容量,会发生阻塞。

数据库中获得ID

获得数据库中的ID,如果获取失败,将停顿一秒,继续尝试获取

func (u *Uid) reload() error {
    var err error
    for {
        err = u.getFromDB()
        if err == nil {
            return nil
        }

        // 如果获取失败,等待
        time.Sleep(time.Second)
    }
}

操作数据库

func (u *Uid) getFromDB() error {
    var (
        maxId int64
        step  int64
    )
    tx, err := u.db.Begin()
    if err != nil {
        return err
    }
    defer tx.Rollback()
    //sql语句
    sqlquery := "select max_id,step from uid where business_id = ? FOR UPDATE "
    err = tx.QueryRow(sqlquery, u.businessId).Scan(&maxId, &step)
    if err != nil {
        return err
    }
    // 更新数据库中uid的最大值
    update := "update uid set max_id = ? where business_id = ?"
    _, err = tx.Exec(update, maxId+step, u.businessId)
    if err != nil {
        return err
    }
    err = tx.Commit()
    if err != nil {
        return err
    }
    u.min = maxId
    u.max = maxId + step
    return nil
}

有了这个数据库自增ID的管理,当我们分布式操作数据库时,就可以保证不会发生冲突了

END

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang技术杂文 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 建表
  • 代码思路
    • 定义结构体绑定sql
      • 新建一个UID
        • 生产ID
        • 数据库中获得ID
        相关产品与服务
        数据库
        云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档