当前位置: 首页 > article >正文

【Go - 超实用,3行代码实现个自增器】

场景

自增器的作用是生成一个唯一的递增序列号。这在一些需要生成自增id的场景十分有用,比如自增的订单号,任务号,序列号。

要点

  • 全局统一:在整个服务体系下,多个服务或者进程,都统一调用这个自增器,来获取自增ID。
  • 严格自增:避免竞争,写冲突造成写覆盖等,导致不严格自增

实现

根据上面要点,需要跨服务进程可以访问,且保障严格自增。综上考虑, 依赖MonogoDB来实现这个自增器,以下是代码实现,

代码

mongodb-conn.go

package main

import (
	"context"
	"os"
	"sync"

	mongo "go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var (
	singletonMongoClient *mongo.Client
	once                 sync.Once
)

var MONGODB_URI = os.Getenv("MONGODB_URI")
var MONGODB_DATABASE = os.Getenv("MONGODB_DATABASE")

func getSingletonMongoClient() *mongo.Client {

	once.Do(func() {
		// 创建连接到 MongoDB 的客户端
		uri := MONGODB_URI
		client, err := mongo.Connect(context.TODO(), options.Client().
			ApplyURI(uri))

		if err != nil {
			panic(err)
		}
		singletonMongoClient = client
	})
	return singletonMongoClient
}
func GetMongoConn() *mongo.Database {
	return getSingletonMongoClient().Database(MONGODB_DATABASE)
}

main.go

package main

import (
	"context"

	bson "go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type UniqSeq struct {
	Key string `bson:"key"`
	Seq int64  `bson:"seq"`
}

func GetNextSeq(key string) (int64, error) {
	conn := GetMongoConn()
	var collectionName = "uniqseqz"
	collection := conn.Collection(collectionName)
	filter := bson.M{"key": key}
	update := bson.M{"$inc": bson.M{"seq": 1}}
	opts := options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)

	var result UniqSeq
	err := collection.FindOneAndUpdate(context.Background(), filter, update, opts).Decode(&result)

	if err != nil {
		return 0, err
	}
	return result.Seq, nil
}

func main() {
	// Test
	key := "T"
	seq, err := GetNextSeq(key)
	if err != nil {
		panic(err)
	}
	println(seq)
}

这里的核心就在下面三行

// 这里是借助了MongoDB $inc 和 upsert特性
// 先按key过滤,找出对应的document,然后upsert,没有就插入一条,有就加一。
// 以此来完成了自增
filter := bson.M{"key": key}
update := bson.M{"$inc": bson.M{"seq": 1}}
opts := options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)

关于竞争,

// 这个操作调用的时候,MongoDB Server端会加锁执行,保障操作的原子性,
// 对于调用方可以看以下一行是原子性的,不用担心写冲突或者写覆盖。
var result UniqSeq
	err := collection.FindOneAndUpdate(context.Background(), filter, update, opts).Decode(&result)

运行

最后可以带入运行一下,

MONGODB_URI="${YOUR_MONGODB_URL}" MONGODB_DATABASE="${YOUR_MONGODB_DATABASE}" go run mongodb-conn.go main.go


http://www.kler.cn/news/305405.html

相关文章:

  • react 安装使用 antd+国际化+定制化主题+样式兼容
  • 【 前端优化】Vue 3 性能优化技巧
  • Java项目: 基于SpringBoot+mybatis+maven服装生产管理系统(含源码+数据库+任务书+开题报告+毕业论文)
  • 【CSS】样式水平垂直居中
  • 果蔬识别系统性能优化之路(四)
  • HarmonyOS开发之使用PhotoViewPicker(图库选择器)保存图片
  • 基于SpringBoot+Vue+MySQL的IT技术交流和分享平台
  • apt:Debian 高级包管理器
  • Pyecharts数据可视化大屏:打造沉浸式数据分析体验
  • MySQL中用with as 解决临时表的问题
  • 【Android】【Bug】使用OSmdroid绘制轨迹断裂问题
  • 数据赋能(202)——开发:数据开发管理——技术方法、主要工具
  • Djourney新手入门基础,AI摄影+AI设计+AI绘画-AIGC作图
  • 【PyCharm】和git安装教程
  • Haskell中的数据交换:通过http-conduit发送JSON请求
  • (k8s)Kubernetes本地存储接入
  • 双指针的用法以及示例
  • Python基础语法(3)上
  • 深入解析 SQLSugar:从基础 CRUD 到读写分离与高级特性详解
  • 基于YOLOv10的光伏板缺陷检测系统
  • 【drools】文档翻译1:入门
  • clip论文阅读(Learning Transferable Visual Models From Natural Language Supervision)
  • Spring Boot母婴商城:打造一站式购物体验
  • 数组及使用方法
  • 【Linux】进程调度与切换
  • 【时时三省】tessy 自动化执行用例:Command line interface(命令行接口)
  • 企业的终端安全该怎么防护?
  • OrionX vGPU 研发测试场景下最佳实践之Jupyter模式
  • Python编码系列—Python抽象工厂模式:构建复杂对象家族的蓝图
  • 数据挖掘顶会ICDM 2024论文分享┆MetaSTC:一种基于聚类和元学习的时空预测框架