分布式自增数据库ID
时间:2022-07-22
本文章向大家介绍分布式自增数据库ID,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
作者 | 陌无崖
转载请联系授权
引言
今天在写项目的时候学习了一个用代码编写的自增的数据库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
- 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 数组属性和方法
- Awesome Kubernetes 系列:第一期
- Mongodb多键索引之数组文档
- 在 Cocos Creator 里画个炫酷的雷达图
- 用shader做一个柿子颜色的过场动画
- mysql 找出最新时间的一条数据
- 【NPM库】- 0x05 - 文件、路径操作
- MySQL中insert阻塞问题的分析
- Fedora32下编译安装Qemu5.1并创建ARM版本Linux虚拟机
- 面试官想问的HashMap,都在这一篇里面了!
- CentOS7下使用Mondo Rescue实现系统全备份
- CentOS7下搭建Rsyslog Server记录远程主机系统日志
- 企业运维经典面试题汇总(4)
- 使用QEMU模拟树莓派Raspberry Pi
- Octave梯度下降法最优化代价函数的一个例子—ML Note 38
- Spring Boot入门系列(十八)mybatis 使用注解实现增删改查,无需xml文件!