MongoDB
作为典型的 NoSQL
数据库拥有优秀的横向扩展能力,不拘束于关系型数据库中的表结构,无需调整便可实现结构变更。
今天就让我们了解下如何在普通 Maven
以及 Spring Boot
工程中集成使用 MongoDB
。
一、Maven集成
1. 依赖管理
在查找依赖时你可能会发现 Mongo
存在两个配置版本 mongo-java-driver
与 mongodb-driver-sync
,前者为旧版依赖其包含异步 API
相对复杂,从 MongoDB 4.0+
开始官方建议使用 mongodb-driver-sync
。
简而言之,如果无兼容历史版本的需要,则优先使用 mongodb-driver-sync
,依赖配置如下:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.10.2</version>
</dependency>
2. 服务连接
在执行数据访问前,最基础的当然还是创建客户端连接对象,代码如下:
public void createClient() {
String host = "localhost";
Integer port = 27017;
List<ServerAddress> serverList = Collections.singletonList(new ServerAddress(host, port));
String database = "admin";
String username = "root";
char[] password = "123456".toCharArray();
MongoClientSettings settings = MongoClientSettings.builder()
// 超时配置
.applyToSocketSettings(builder -> {
builder.connectTimeout(60, TimeUnit.SECONDS);
builder.readTimeout(60, TimeUnit.SECONDS);
})
.applyToClusterSettings(builder -> {
builder.serverSelectionTimeout(60, TimeUnit.SECONDS).build();
// 服务信息
builder.hosts(serverList)
})
// 账号信息
.credential(MongoCredential.createScramSha256Credential(username, database, password))
.build();
// 创建客户端
MongoClient client = MongoClients.create(settings);
}
3. URI连接
MongoDB
支持多种连接格式,除了上述的连接方式外 MongoDB
同时支持以 URI
方式,其连接格式如下:
mongodb://<username>:<passsword>@<host>:<port>/<collection>
需注意一点,当用户名或密码中包含特殊字符时,在配置 uri
时需要替换为对应的转义字符,否则将无法连接。
常用的特殊字符及其转义字符参照下表:
字符 | 编码 |
---|---|
@ | %40 |
: | %3A |
/ | %2F |
? | %3F |
# | %23 |
& | %26 |
= | %3D |
其客户端创建类似,将上述的 credential()
替换为 applyConnectionString()
即可,实现代码如下:
String url = "mongodb://root:123456@192.168.0.21:27017/test_col?authSource=admin";
MongoClientSettings settings = MongoClientSettings.builder()
// 超时配置
.applyToSocketSettings(builder -> {
builder.connectTimeout(60, TimeUnit.SECONDS);
builder.readTimeout(60, TimeUnit.SECONDS);
})
.applyToClusterSettings(builder -> {
builder.serverSelectionTimeout(60, TimeUnit.SECONDS).build();
})
// 服务信息
.applyConnectionString(new ConnectionString(url))
.build();
3. 数据新增
想要实现新增数据则十分简单,在获取 MongoCollection
实例后通过相应的 insertOne()
或 insertMany()
方法即可。
完整调用实现代码如下:
public class MongoRepository implements AutoCloseable {
private final String database;
private final MongoClient mongoClient;
public MongoRepository(String database, MongoClient mongoClient) {
this.database = database;
this.mongoClient = mongoClient;
}
@Override
public void close() throws Exception {
if (mongoClient != null) {
mongoClient.close();
}
}
protected MongoDatabase getDatabase() {
return mongoClient.getDatabase(database);
}
public <T> void insert(String collection, T t, Class<T> tClass) {
MongoCollection<T> mongoCollection = getDatabase().getCollection(collection, tClass);
mongoCollection.insertOne(t);
}
public <T> void insertAll(String collection, List<T> list, Class<T> tClass) {
MongoCollection<T> mongoCollection = getDatabase().getCollection(collection, tClass);
mongoCollection.insertMany(list);
}
}
4. 数据查询
MongoDB
查询数据与新增方式类似,这里直接通过代码演示:
public <T> void count(String collection, Map<String, ?> condition, Class<T> tClass) {
MongoCollection<T> mongoCollection = getDatabase()
.getCollection(collection, tClass);
mongoCollection.countDocuments(new Document(condition));
}
public <T> T findOne(String collection, Map<String, ?> condition, Class<T> tClass) {
MongoCollection<T> mongoCollection = getDatabase()
.getCollection(collection, tClass);
return mongoCollection.find(new Document(condition)).first();
}
public <T> List<T> find(String collection, Map<String, ?> condition, Class<T> tClass) {
MongoCollection<T> mongoCollection = getDatabase()
.getCollection(collection, tClass);
FindIterable<T> iterable = mongoCollection.find(new Document(condition));
List<T> list = new ArrayList<>();
for (T t : iterable) {
list.add(t);
}
return list;
}
5. 数据删除
同理,文档记录删除方式如下不再展开介绍。
public <T> boolean delete(String collection, Map<String, ?> condition, Class<T> tClass) {
MongoCollection<T> mongoCollection = getDatabase()
.getCollection(collection, tClass);
return mongoCollection.deleteMany(new Document(condition)).getDeletedCount() > 0;
}
public <T> boolean deleteOne(String collection, Map<String, ?> condition, Class<T> tClass) {
MongoCollection<T> mongoCollection = getDatabase()
.getCollection(collection, tClass);
return mongoCollection.deleteOne(new Document(condition)).getDeletedCount() > 0;
}
二、Spring集成
1. 依赖管理
在 Spring Boot
中依赖就十分简单了,引入对应的 starter
即可,依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2. 连接配置
引入依赖后需在项目中配置 MongoDB
的连接信息,在 application.yml
中添加下述内容。
这里采用 URI
方式连接,与之前 Maven
方式集成中提到的类似,如果用户名或密码包含特殊字符转替换为转义字符。
spring:
data:
mongodb:
uri: mongodb://root:123456@localhost:27017/test_collection?authSource=admin
3. 数据新增
完成配置后即可开始相应访问交互,与 Maven
中不同的是你可以通过 MongoTemplate
便可轻易的实现与 MongoDB
的相应交互。
在 MongoDB
中提供了两种新增接口 save()
与 insert()
,二者最大的区别前者新增时若数据已存在则会报错失败,而 insert()
方法则会直接覆盖旧数据。
相应的新增方法实现如下:
@Component
public class MongoRepository {
@Autowired
private MongoTemplate mongoTemplate;
public <T> void save(T t) {
mongoTemplate.save(t);
}
public <T> void insert(T t) {
mongoTemplate.insert(t);
}
public <T> void insertAll(Collection<T> collection) {
mongoTemplate.insertAll(collection);
}
}
4. 数据查询
在 MongoDB
中通过 Criteria
与 Query
构建查询条件,常用的查询接口参考下表:
方法 | 描述 |
---|---|
count() | 查询匹配的记录条数。 |
find() | 返回所有匹配的记录结果。 |
findOne() | 返回匹配记录结果中的一条。 |
findById() | 根据文档 ID 精准匹配查询。 |
表中所列接口其相应的实现如下:
@Component
public class MongoRepository {
@Autowired
private MongoTemplate mongoTemplate;
public <T> long count(Class<T> tClass, Map<String, Object> condition) {
return mongoTemplate.count(createQuery(condition), tClass);
}
public <T> T find(Class<T> tClass, Map<String, Object> condition) {
return mongoTemplate.findOne(createQuery(condition), tClass);
}
public <T> T findById(Object id, Class<T> tClass) {
return mongoTemplate.findById(id, tClass);
}
public <T> List<T> findAll(Class<T> tClass, Map<String, Object> condition) {
return mongoTemplate.find(createQuery(condition), tClass);
}
protected Query createQuery(Map<String, Object> conditions) {
Criteria criteria = new Criteria();
for (Map.Entry<String, Object> entry : conditions.entrySet()) {
criteria.and(entry.getKey()).is(entry.getValue());
}
return new Query(criteria);
}
}