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

1,456 阅读3分钟

想要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” 在这里插入图片描述

生成keyFile
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。

sudo chmod 600 keyFile
sudo chown 999:999 keyFile

容器外 在这里插入图片描述 容器里

在这里插入图片描述 当keyFile文件准备好以后,就可以根据上面的docker-compose.yml启动容器。

初始化

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

docker exec -it mongodb /bin/bash

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

mongo -u admin --authenticationDatabase admin

在这里插入图片描述

执行初始化

rs.initiate()

显示一下就说明成功了 在这里插入图片描述 到这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后直接连接会报这个错。 在这里插入图片描述

我们首先进入容器,查看当前容器的hostname 在这里插入图片描述 使用上面提到的方式,使用admin账号登陆mongo,查看config

rs.config()

在这里插入图片描述 正如上述所说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})

在这里插入图片描述 改完以后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都是同一个了。