如何在Golang中使用MongoDB的事务

2023-05-16

如何在Golang中使用MongoDB的事务

  • 一、Mongo中的事务
      • 1.Mongo新特性
      • 2.基于会话的事务
      • 3.事务相关命令
  • 二、搭建Mongo副本集
      • 1. 安装MongoDB
      • 2. 环境变量配置
      • 3. 创建副本集目录
          • 3.1 创建主节点相关目录
          • 3.2 创建副节点相关目录
          • 3.3 创建仲裁节点相关目录
      • 4. 创建副本集认证的key文件
      • 5 修改MongoDB配置文件
          • 5.1 主节点配置文件
          • 5.2 副节点配置文件
          • 5.3 仲裁节点配置文件
      • 6. 使用Systemd对Mongo服务进行管理
          • 6.1 主节点配置
          • 6.2 副节点配置
          • 6.3 仲裁节点配置
      • 7. 启动MongoDB服务
          • 7.1 启动节点
          • 7.2 查看节点状态
      • 8. 创建用户,并初始化副本集
  • 三、在Go代码中实现Mongo事务
      • 1. 下载驱动包
      • 2. 代码例子

一、Mongo中的事务

1.Mongo新特性

首先,我们必须知道的是,Mongo的事务的在版本4.0时的新特性,也就是说,如果Mongo的版本是在4.0之前的,那么是不支持事务的,因此,我们的Mongo需要是4.0以上的版本。

2.基于会话的事务

其次,Mongo的事务是比较有意思的,Mongo要开启事务支持,需要搭建副本集(Replica Sets)。而且,Mongo的事务是和会话(Session)相关联的,一个会话同一时刻只能开启一个事务操作,当一个会话断开的时候,这个会话中的事务也会结束。

3.事务相关命令

Mongo中的事务相关命令如下:

//开启一个会话
sess = db.getMongo().startSession()
//开启事务
sess.startTransaction()
//回滚
sess.abortTransaction()
//提交
sess.commitTransaction()
//结束会话
sess.endSession()

二、搭建Mongo副本集

以下搭建副本集以Centos为例,并在同一个机子上进行搭建

1. 安装MongoDB

首先在MongoDB官网下载对应系统和版本的MongoDB包,如:

[root@vm1 ~]# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.10.tgz

解压tgz包到/usr/local/目录下,并给目录重命名一下

[root@vm1 ~]# tar -zxvf mongodb-linux-x86_64-rhel70-4.4.10.tgz -C /usr/local/
[root@vm1 ~]# mv /usr/local/mongodb-linux-x86_64-rhel70-4.4.10/ /usr/local/mongodb-4.4.10/

2. 环境变量配置

# 修改环境变量
[root@vm1 ~]# vi /etc/profile

在末尾添加一行:export PATH=$PATH:/usr/local/mongodb-4.4.10/bin

# 使环境变量生效
[root@vm1 ~]# source /etc/profile

3. 创建副本集目录

3.1 创建主节点相关目录
[root@vm1 ~]# cd /usr/local/mongodb-4.4.10/
[root@vm1 mongodb-4.4.10]# mkdir primary
[root@vm1 mongodb-4.4.10]# cd primary
[root@vm1 primary]# mkdir data logs config pid
3.2 创建副节点相关目录
[root@vm1 primary]# cd ..
[root@vm1 mongodb-4.4.10]# mkdir secondary
[root@vm1 mongodb-4.4.10]# cd secondary
[root@vm1 secondary]# mkdir data logs config pid
3.3 创建仲裁节点相关目录
[root@vm1 secondary]# cd ..
[root@vm1 mongodb-4.4.10]# mkdir arbiter
[root@vm1 mongodb-4.4.10]# cd arbiter
[root@vm1 arbiter]# mkdir data logs config pid

4. 创建副本集认证的key文件

[root@vm1 arbiter]# cd ..
[root@vm1 mongodb-4.4.10]# openssl rand -base64 90 -out mongo.keyfile
[root@vm1 mongodb-4.4.10]# chmod 400 mongo.keyfile

5 修改MongoDB配置文件

5.1 主节点配置文件
[root@vm1 mongodb-4.4.10]# cd primary/
[root@vm1 primary]# vi config/mongod.conf

添加内容如下:

systemLog:
    #MongoDB发送所有日志输出的目标指定为文件
    destination: file
    #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
    path: "/usr/local/mongodb-4.4.10/primary/logs/mongod.log"
    #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾
    logAppend: true
storage:
    #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod
    dbPath: "/usr/local/mongodb-4.4.10/primary/data"
    journal:
         #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
        enabled: true
processManagement:
    #启用在后台运行mongos或mongod进程的守护进程模式。
    fork: true
    #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
    pidFilePath: "/usr/local/mongodb-4.4.10/primary/pid/mongod.pid"
net:
    #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
    #bindIpAll: true
    #服务实例绑定的IP
    bindIp: 0.0.0.0
    #bindIp
    #绑定的端口
    port: 27017
replication:
    #副本集的名称
    replSetName: "my-rs"
security:
    #副本集密钥文件
    keyFile: "/usr/local/mongodb-4.4.10/mongo.keyfile"
    #副本集认证方式
    clusterAuthMode: "keyFile"
5.2 副节点配置文件
[root@vm1 primary]# cd ../secondary/
[root@vm1 secondary]# vi config/mongod.conf

添加内容如下:

systemLog:
    #MongoDB发送所有日志输出的目标指定为文件
    destination: file
    #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
    path: "/usr/local/mongodb-4.4.10/secondary/logs/mongod.log"
    #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾
    logAppend: true
storage:
    #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod
    dbPath: "/usr/local/mongodb-4.4.10/secondary/data"
    journal:
         #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
        enabled: true
processManagement:
    #启用在后台运行mongos或mongod进程的守护进程模式。
    fork: true
    #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
    pidFilePath: "/usr/local/mongodb-4.4.10/secondary/pid/mongod.pid"
net:
    #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
    #bindIpAll: true
    #服务实例绑定的IP
    bindIp: 0.0.0.0
    #bindIp
    #绑定的端口
    port: 27018
replication:
    #副本集的名称
    replSetName: "my-rs"
security:
    #副本集密钥文件
    keyFile: "/usr/local/mongodb-4.4.10/mongo.keyfile"
    #副本集认证方式
    clusterAuthMode: "keyFile"
5.3 仲裁节点配置文件
[root@vm1 secondary]# cd ../arbiter/
[root@vm1 arbiter]# vi config/mongod.conf

添加内容如下:

systemLog:
    #MongoDB发送所有日志输出的目标指定为文件
    destination: file
    #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
    path: "/usr/local/mongodb-4.4.10/arbiter/logs/mongod.log"
    #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾
    logAppend: true
storage:
    #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod
    dbPath: "/usr/local/mongodb-4.4.10/arbiter/data"
    journal:
         #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
        enabled: true
processManagement:
    #启用在后台运行mongos或mongod进程的守护进程模式。
    fork: true
    #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
    pidFilePath: "/usr/local/mongodb-4.4.10/arbiter/pid/mongod.pid"
net:
    #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
    #bindIpAll: true
    #服务实例绑定的IP
    bindIp: 0.0.0.0
    #bindIp
    #绑定的端口
    port: 27019
replication:
    #副本集的名称
    replSetName: "my-rs"
security:
    #副本集密钥文件
    keyFile: "/usr/local/mongodb-4.4.10/mongo.keyfile"
    #副本集认证方式
    clusterAuthMode: "keyFile"

6. 使用Systemd对Mongo服务进行管理

6.1 主节点配置
[root@vm1 arbiter]# vi /usr/lib/systemd/system/mongo-primary.service

添加内容如下

[Unit]
Description=mongodb primary

[Service]
ExecStart=/usr/local/mongodb-4.4.10/bin/mongod -f /usr/local/mongodb-4.4.10/primary/config/mongod.conf
ExecStop=/bin/kill -INT $MAINPID
PIDFile=/usr/local/mongodb-4.4.10/primary/pid/mongod.pid

[Install]
WantedBy=multi-user.target

添加为开机启动

[root@vm1 arbiter]# systemctl enable mongo-primary
6.2 副节点配置
[root@vm1 arbiter]# vi /usr/lib/systemd/system/mongo-secondary.service

添加内容如下

[Unit]
Description=mongodb secondary

[Service]
ExecStart=/usr/local/mongodb-4.4.10/bin/mongod -f /usr/local/mongodb-4.4.10/secondary/config/mongod.conf
ExecStop=/bin/kill -INT $MAINPID
PIDFile=/usr/local/mongodb-4.4.10/secondary/pid/mongod.pid

[Install]
WantedBy=multi-user.target

添加为开机启动

[root@vm1 arbiter]# systemctl enable mongo-secondary
6.3 仲裁节点配置
[root@vm1 arbiter]# vi /usr/lib/systemd/system/mongo-arbiter.service

添加内容如下

[Unit]
Description=mongodb arbiter

[Service]
ExecStart=/usr/local/mongodb-4.4.10/bin/mongod -f /usr/local/mongodb-4.4.10/arbiter/config/mongod.conf
ExecStop=/bin/kill -INT $MAINPID
PIDFile=/usr/local/mongodb-4.4.10/arbiter/pid/mongod.pid

[Install]
WantedBy=multi-user.target

添加为开机启动

[root@vm1 arbiter]# systemctl enable mongo-arbiter

7. 启动MongoDB服务

7.1 启动节点
[root@vm1 arbiter]# systemctl start mongo-primary mongo-secondary mongo-arbiter
7.2 查看节点状态
[root@vm1 arbiter]# systemctl status mongo-primary mongo-secondary mongo-arbiter

8. 创建用户,并初始化副本集

[root@vm1 mongodb-4.4.10]# mongo --port 27017
> use admin
> db.createUser({user:"root", pwd:"root", roles:["root"]})
> config={
    "_id": "my-rs",
    "members": [
        {
            "_id": 0,
            "host": "127.0.0.1:27017",
            "priority": 2
        },
        {
            "_id": 1,
            "host": "127.0.0.1:27018",
            "priority": 1
        },
        {
            "_id": 2,
            "host": "127.0.0.1:27019",
            "arbiterOnly": true
        }
    ]
}
> rs.initiate(config)
> rs.status()

三、在Go代码中实现Mongo事务

1. 下载驱动包

直接执行下面的命令获取Golang的官方Mongo驱动包

go get -u go.mongodb.org/mongo-driver/mongo

2. 代码例子

使用事务时,特别要注意该用哪个context,在进行任何的db操作,不管是插入还是更新,都必须使用函数参数的那个sessionCtx,否则事务是无法生效的。另外在进行提交和回滚的时候,需要使用context.Background(),这是因为提交和回滚不应被context超时等因素影响。

package main

import (
	"context"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"time"
)

//mongo连接参数
const (
	user     = "root"
	pwd      = "root"
	hosts    = "127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019"
	mongoOpt = "replicaSet=my-rs"
	auth     = "admin"
	timeout  = time.Duration(3000) * time.Millisecond
)

//mongo文档结构体
type student struct {
	Name   string `bson:"name"`
	Gender string `bson:"gender"`
	Age    int    `bson:"age"`
}

func main() {
	//设置连接参数
	uri := fmt.Sprintf("mongodb://%s:%s@%s/%s?%s",
		user, pwd, hosts, mongoOpt, auth)
	opt := options.Client().ApplyURI(uri).SetSocketTimeout(timeout)

	//创建一个context上下文
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	//获得一个mongo client
	client, err := mongo.Connect(ctx, opt)
	if err != nil {
		logs.Error("connect mongo failed, err:%s", err.Error())
		return
	}

	//ping一下mongo
	err = client.Ping(ctx, nil)
	if err != nil {
		logs.Error("ping mongo failed, err:%s", err.Error())
		return
	}

	//设定连接的数据库和集合
	database := "school"
	collection := "student"
	//构造插入的数据
	students := []interface{}{
		student{
			Name:   "Michael",
			Gender: "Male",
			Age:    21,
		},
		student{
			Name:   "Alice",
			Gender: "Female",
			Age:    19,
		},
	}

	//在会话中使用mongo
	if err = client.UseSession(ctx, func(sessionContext mongo.SessionContext) error {
		//开启事务
		if err := sessionContext.StartTransaction(); err != nil {
			return err
		}

		//插入数据
		if _, err := client.Database(database).Collection(collection).InsertMany(sessionContext, students); err != nil {
			if err := sessionContext.AbortTransaction(context.Background()); err != nil {
				//回滚事务
				logs.Error("mongo transaction rollback failed, %s", err.Error())
				return err
			}
			return err
		}
		//提交事务
		return sessionContext.CommitTransaction(context.Background())
	}); err != nil {
		logs.Error("insert failed, err:%s", err.Error())
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在Golang中使用MongoDB的事务 的相关文章

随机推荐

  • pytorch中的dim=0,=1,=2,在高纬度上的一些个人理解

    编译工具 xff1a Pycharm 张量工具 xff1a pytorch 目前大部分博主对dim的讲解大多停留在低维 xff0c 在这里我说一下高维的情况 xff0c 先看图 xff1a 在上图中 xff0c 我们用pytorch中声明了
  • Makefile 学习笔记

    Makefile 学习笔记 1 hello world b a 64 echo span class token string 34 hello b 34 span a 64 echo span class token string 34
  • Linux Git 学习笔记

    1 版本的创建 xff1a span class token function git span init span class token comment 初始化 span span class token function git sp
  • GDB学习记录

    1 基本用法 在gcc g 43 43 参数里加上 g xff0c 生成的文件会包含调试程序 xff0c 不加该参数则不包含调试程序 xff0c 不利于gdb调试 基本命令 xff1a list或者l xff1a 显示调试对象的代码文本内容
  • 【Python】输入3个数,输出它们的乘积。

    问题描述 xff1a 输入3个数 xff0c 输出它们的乘积 效果 输入第一个数 xff1a 5 输入第二个数 xff1a 5 输入第三个数 xff1a 8 200 进程已结束 xff0c 退出代码 0 代码 xff1a x 61 int
  • For frame [laser]: Fixed Frame [map] does not exist此类问题解决

    又是一个容易被新手忽略的小问题 当我们使用rviz时 xff0c 比如运行雷达后没有点云数据 xff0c 即使我们能看到发布了 scan话题 像这样 xff0c 就是没点云图 xff0c 看一下laserscan提示的错误 xff1a Fo
  • VMware虚拟机如何为GPU直通启用

    查阅了很多资料是 目前的我的电脑显卡不支持 xff0c 基本上N卡的好多常用卡都不支持 具体可以查看以下内容 https www dell com support article zh hk sln288103 E5 A6 82 E4 BD
  • pycharm修改远程服务器文件后,上传报错无法传输文件 ‘D:\xxx‘: could not write to xxxx

    原因是文件权限问题 A用户在服务器创建文件 xff0c 然后让B用户进入改文件操作代码 xff0c 这个时候会遇到权限问题 解决办法 xff1a cd 到需要修改权限的目录下 运行 sudo chmod 777 hhs R xff08 hh
  • 故障案例:连接服务器失败/服务器无法上网

    今日内容 安装过程补充 安装界面其他内容 磁盘分区 xshell优化 远程连接排错流程 远程连接常见故障原因 Linux基本规则 Linux常见命令 和 快捷键 运维新手学习什么内容面试 招聘者 CEO 怎么判断这个人是否有能力 0 态度
  • cmd中conda无法使用

    运行后会弹出一个conda exe窗口但是马上就会关闭 但是在命令行依旧没有任何反应 去查看了一下path中的环境变量也都存在 进入Anaconda Prompt中输入conda也是这样 有没有大佬知道为什么啊
  • 阿里云生活物联网平台搭建

    总括 xff1a 本项目主要实现上位机可以实时显示单片机 xff08 下位机 xff09 采集的数据 xff0c 同时上位机也可以发送指令控制单片机 在项目中需要用到上位机 xff0c 目前采用 阿里云生活物联网平台 提供的手机APP xf
  • python作业

    这里写自定义目录标题 python简单程序1 九九乘法表2 求1 2 43 3 4 43 5 99的所有数的和3 输入一行字符 xff0c 分别统计出其中英文字母 空格 数字和其它字符的个数4 python求阶乘之和 xff0c 1 xff
  • linux突然所有命令未找到,显示bash: xxxxx: command not found...

    出现这个问题是因为系统的环境变量没有正确配置造成的 xff0c 造成这个原因有很多 xff0c 解决的方式有两种 一 xff1a 直接在linux命令行界面输入如下 xff0c 然后回车 xff08 导入环境变量 xff0c 以及shell
  • HTML5——如何在网页中加入图片和超链接。

    声明 xff1a 此页内容极度简单 xff0c 觉得low的话我可以不看 寻找图片 xff0c 把图片的位置记好 xff0c 并且重命名 xff0c 方便寻找 写出基本框架 xff0c 引用 lt img gt 标签 找出你需要跳转的网页
  • MacOS VsCode C++连接mysql

    使用Cmake 1 CmakeLists txt配置 cmake minimum required VERSION 3 18 project MYSQL include directories 34 usr local mysql 8 0
  • Linux系统MySQL8版本修改密码的方法

    MySQL8和MySQL5修改密码的sql差别很大 xff0c 用了MySQL5的修改方法还可能掉坑里面 xff0c 本文介绍8版本的修改方法 1 登录MySQL mysql uroot p密码 2 切换到user数据库 use mysql
  • 用warp给minio测压

    拉取Docker镜像 看到拉取的warp镜像已经跑起来了 这里的docker run minio warp v0 4 5 h 就是查看 help文档 xff0c 上面那条语句原型是docker run minio warp v0 4 5 w
  • SpringBoot中的service报空指针异常

    SpringBoot中的service报空指针异常 异常排查 xff1a 1 检查Service是否加了 64 Service注解 2 Controller中的属性service是否加了 64 Autowired注解 3 检查所写的对外接口
  • 本地上运行正常,但是部署到了服务器却一直验证码错误(Nginx反向代理导致的session丢失问题)

    最近做一个课程项目 xff0c 在本地开发完后部署到服务器上 xff0c 一切都比较顺利 但是在登录用户的时候却一直显示验证码错误 xff01 xff01 xff01 排错过程 1 代码检查2 参数检查3 外层检查4 直接访问5 通过Ngi
  • 如何在Golang中使用MongoDB的事务

    如何在Golang中使用MongoDB的事务 一 Mongo中的事务1 Mongo新特性2 基于会话的事务3 事务相关命令 二 搭建Mongo副本集1 安装MongoDB2 环境变量配置3 创建副本集目录3 1 创建主节点相关目录3 2 创