想要 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 都是同一個了。