【mongo事务】使用docker-compose启动mongo,‘单副本模式‘实现支持事务

想要mongo支持事务的首要条件是mongo版本4.x 以上,且为复制集模式。由于很多时候使用mongo都不需要部署多副本,但是想支持事务,所以可以使用‘单副本模式’,既能保证mongo实例只有一个,又是复制集模式。
本文使用mongo5.0.8作为样例。

本文只是日常遇到问题的小记,如有错误,欢迎指出。

首先给出docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: '3.0'
services:
mongo:
image: mongo:5.0.8
restart: unless-stopped
container_name: mongodb
command: --replSet rs0 --bind_ip_all --keyFile /data/mongodb/keyFile
environment:
TZ: 'Asia/Shanghai'
#用户名密码
MONGO_INITDB_ROOT_USERNAME: 'admin'
MONGO_INITDB_ROOT_PASSWORD: 'password'
ports:
- 27017:27017
volumes:
- ./mongodb/data:/data/db
- ./mongodb/keyFile:/data/mongodb/keyFile

准备keyFile

本人粗略测试在4.x版本不需要使用keyFile,但是在5.x版本是必须要KeyFile的,不然会报 “BadValue: security.keyFile is required when authorization is enabled with replica sets”
mongo启动日志

生成keyFile
1
openssl rand -base64 128 > ./mongodb/keyFile

其中 ./mongodb/keyFile 是指定生成文件的名字以及在哪一个文件夹下

设置权限以及所属用户

keyFile文件的权限必须为600,如果权限太大,启动时会报“error opening file: /data/mongodb/keyFile: bad file”

当权限改为600以后还需要把keyFile文件的所属用户和用户组改为mongodb不然在启动时会报”permissions on /data/mongodb/keyFile are too open”

由于使用容器启动所以需要把keyFile文件的所属用户和用户组 改为999,这样容器会自动把keyFile文件的所属用户和用户组改为mongodb。

1
2
sudo chmod 600 keyFile
sudo chown 999:999 keyFile

容器外

容器里


当keyFile文件准备好以后,就可以根据上面的docker-compose.yml启动容器。

初始化

容器启动后这时mongo还不能使用,还需要进入容器内初始化复制集。
进入容器

1
docker exec -it mongodb /bin/bash

用刚刚设置的用户名密码进入mongo

1
mongo -u admin --authenticationDatabase admin

执行初始化

1
rs.initiate()

显示一下就说明成功了

到这mongo就算是启动完成了。

spring boot项目配置

要想实现事务还需要在项目中进行配置

spring boot 版本: 2.1.6.RELEASE

1
2
3
4
5
6
7
8
9
@Configuration
@Slf4j
public class MongoTransactionConfig {
@Bean
MongoTransactionManager transactionManager(MongoDbFactory factory){
log.warn("开启mongo事务");
return new MongoTransactionManager(factory);
}
}

在spring boot高版本中MongoDbFactory被弃用需要换成MongoDatabaseFactory

spring boot 版本:2.6.1

1
2
3
4
5
6
7
8
9
@Configuration
@Slf4j
public class MongoTransactionConfig {
@Bean
MongoTransactionManager transactionManager(MongoDatabaseFactory factory){
log.warn("开启mongo事务");
return new MongoTransactionManager(factory);
}
}

添加配置类以后只需要在方法上加入@Transactional注解就可以实现mongo事务了。


!!!新增!!!
很多时候我们会保留挂载出来的数据,重新构建容器,由于docker在每次构建新容器时都会为容器随机分配一个hostname。但因为我们还是使用上一个容器挂载出来的数据,这就导致mongo副本集配置的hostname还是上一个容器,这就导致新启动的mongo不能用。因此我们只需要改变mongo副本集配置的hostname,就能解决这个问题

当我们启动mongo后直接连接会报这个错。

我们首先进入容器,查看当前容器的hostname

使用上面提到的方式,使用admin账号登陆mongo,查看config

1
rs.config()


正如上述所说config里的hostname与当前容器的不一样

方法1:更改hostname

1.获取副本集配置

1
config=rs.conf()

2.可以根据上面配置json的格式可以知道hostname的位置,从而对他进行重新赋值(将host改为当前容器的host)

1
config.members[0].host="c3e9261f8a04:27017"

3.最后更新config

1
rs.reconfig(config, {force : true})


改完以后mongo就能正常启动了

方法2:在yaml中指定hostname

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
version: '3.0'
services:
mongo:
hostname: mongo501
image: mongo:5.0.8
restart: unless-stopped
container_name: mongodb
command: --replSet rs0 --bind_ip_all --keyFile /data/mongodb/keyFile
environment:
TZ: 'Asia/Shanghai'
#用户名密码
MONGO_INITDB_ROOT_USERNAME: 'admin'
MONGO_INITDB_ROOT_PASSWORD: 'password'
ports:
- 27017:27017
volumes:
- ./mongodb/data:/data/db
- ./mongodb/keyFile:/data/mongodb/keyFile

这样的话每次新建的容器的hostname都是同一个了。


【mongo事务】使用docker-compose启动mongo,‘单副本模式‘实现支持事务
https://blog.wilsonj.ltd/2022/10/17/blog001/
作者
WilsonJ
发布于
2022年10月17日
许可协议