您可以使用 MongoTemplate 上的 executeCommand(...) 方法获取 MongoDB 驱动程序的 MongoDatabase.runCommand() 方法。这些方法还将异常转换为 Spring 的 DataAccessException 层次结构异常。
运行命令的方法定义如下:
Document executeCommand (Document command) 运行一个Mongo DB命令。
Document executeCommand (Document command, ReadPreference readPreference) 使用给定的可为空的 MongoDB ReadPreference 运行 MongoDB 命令。
Document executeCommand (String jsonCommand) 运行一个表示为 JSON 字符串的 MongoDB 命令。
在副本集 Replica Set 中才涉及到 ReadPreference 策略的设置,默认情况下,读写都是分发到 Primary(主)节点执行,但是对于写少读多的情况,我们希望进行读写分离来分摊压力,所以希望使用 Secondary(从)节点来进行读取,Primary 只承担写的责任(实际上写只能分发到 Primary 节点,不可修改)。
MongoDB 有 5 种 ReadPreference 策略,分别如下:
primary 主节点,默认模式,读操作只在主节点,如果主节点不可用,报错或者抛出异常。
primaryPreferred 首选主节点,大多情况下读操作在主节点,如果主节点不可用,如故障转移,读操作在从节点。
secondary 从节点,读操作只在从节点, 如果从节点不可用,报错或者抛出异常。
secondaryPreferred 首选从节点,大多情况下读操作在从节点,特殊情况(如单主节点架构)读操作在主节点。
nearest 最邻近节点,读操作在最邻近的成员,可能是主节点或者从节点。
(1)application.properties 配置文件
# Log logging.level.root=debug # MongoDB spring.data.mongodb.uri=mongodb://localhost:27017/test
(2)AppConfig.java 配置类,配置 MongoTemplate 对象
import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.MongoDatabaseFactory; import org.springframework.data.mongodb.core.MongoTemplate; /** * 配置 MongoTemplate * @author hxstrive.com 2022/12/23 */ @Slf4j @Configuration public class AppConfig { @Bean public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDatabaseFactory) { log.info("mongoTemplate({}, {})", mongoDatabaseFactory); return new MongoTemplate(mongoDatabaseFactory); } }
(3)集合 person 对应的实体
import lombok.Builder; import lombok.Data; import lombok.ToString; @Data @ToString @Builder public class Person { /** 用户ID */ private int id; /** 用户姓名 */ private String name; /** 年龄 */ private int age; }
(4)客户端代码,说明见注释。
import com.hxstrive.springdata.mongodb.entity.Person; import com.mongodb.ReadPreference; import org.bson.Document; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.mongodb.core.MongoTemplate; /** * 运行 MongoDB 命令示例 * @author hxstrive.com */ @SpringBootTest public class RunningCommandsDemo { @Autowired private MongoTemplate mongoTemplate; @BeforeEach public void init() { mongoTemplate.dropCollection(Person.class); // 准备数据 mongoTemplate.insert(Person.builder().id(100).name("Tom").age(27).build()); mongoTemplate.insert(Person.builder().id(200).name("Helen").age(30).build()); mongoTemplate.insert(Person.builder().id(300).name("Bill").age(47).build()); mongoTemplate.insert(Person.builder().id(400).name("Joe").age(20).build()); } @Test public void executeCommand() { // 获取 person 集合中文档数量 Document command = new Document(); command.append("count", "person"); Document result = mongoTemplate.executeCommand(command); System.out.println(result); // 结果: // Document{{n=4, ok=1.0}} } @Test public void executeCommand2() { // 获取 person 集合中文档数量 Document command = new Document(); command.append("count", "person"); // 指定读策略 // ReadPreference 主要控制客户端driver从副本集(Replica Set)读数据的时候的策略 ReadPreference readPreference = ReadPreference.primary(); Document result = mongoTemplate.executeCommand(command, readPreference); System.out.println(result); // 结果: // Document{{n=4, ok=1.0}} } @Test public void executeJSON() { // 获取 person 集合中文档数量 Document result = mongoTemplate.executeCommand("{count: 'person'}"); System.out.println(result); // 结果: // Document{{n=4, ok=1.0}} } }