banner
WilsonJ

WilsonJ

github
follow

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

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

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

首先给出 docker-compose.yml#

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”
image

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

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

设置权限以及所属用户#

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

image

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

image

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

sudo chmod 600 keyFile
sudo chown 999:999 keyFile

容器外

image

容器里

image

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

初始化#

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

docker exec -it mongodb /bin/bash

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

mongo -u admin --authenticationDatabase admin

image

执行初始化

rs.initiate()

显示一下就说明成功了

image

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

spring boot 项目配置#

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

spring boot 版本: 2.1.6.RELEASE

@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

@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 后直接连接会报这个错。

image

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

image

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

rs.config()

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

方法 1:更改 hostname#

1. 获取副本集配置

config=rs.conf()

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

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

3. 最后更新 config

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

image

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

方法 2:在 yaml 中指定 hostname#

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 都是同一个了。

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。