【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

Go-Ethereum(Geth)是一个实现了Ethereum协议的开源客户端,其中EIP-1559是关于交易费用处理的一项重要升级,它引入了基础费和上限费的概念。在EIP-1559中,用户需要支付两部分费用:一部分是固定的基础费,用于保证网络的基本服务;另一部分是可变的上限费,取决于市场供需。 下面是一个简化的示例,展示了如何在Golang中通过`go-ethereum`库实现基于EIP-1559的交易创建: ```go package main import ( "context" "fmt" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" ) func main() { // 连接到本地的Ethereum节点(假设你已经启动了一个Geth节点) client, err := rpc.Dial("http://localhost:8545") if err != nil { fmt.Println("Failed to connect to node:", err) return } // 创建一个新的交易 senderAddress := "0xYourSenderAddress" // 用实际地址替换 receiverAddress := "0xYourReceiverAddress" // 用实际地址替换 value := types.NewUnits(10) // 转账价值,单位为wei feeCap := types.NewUnits(1) // 上限费,这里设为较低值以便于演示 maxPriorityFeePerGas := types.NewUnits(1) // 最高优先级费用率 // 使用EIP-1559计算交易费用 transaction, _, _ := client.Eth.SendTransaction( rpc.Transaction{ From: senderAddress, To: receiverAddress, Value: value, GasLimit: types.GWei(21000), // 高效交易一般设置较高的gas limit FeeCap: feeCap, PriorityFeeCap: maxPriorityFeePerGas, MaxFeePerGas: maxPriorityFeePerGas, // 也可以省略,因为会被FeeCap自动控制 }, ) // 输出交易哈希便于跟踪 hashStr := hexutil.Encode(transaction.Hash()) fmt.Printf("Transaction hash: %s\n", hashStr) } ``` 请注意,这只是一个基本示例,实际应用中还需要处理错误、网络延迟以及链上状态的变化等复杂情况。同时,EIP-1559的具体实现细节可能会随着Ethereum主网的更新而有所变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值