我们知道,MongoDB的三大基本元素是数据库,集合,文档,而这一章,我们将学习如何使用MongoDB Java Driver API来操作数据库。本章不会谈到所有的API,只是起一个抛砖引玉的方式。本章内容如下:
1. 数据库基本操作
2. 执行db.adminCommand命令
我们还是用代码来驱动讲解,而不是讲解来驱动代码。在本章中,甚至以后的章节中,都会沿用使用单元测试代码的方式给出示例代码,所以,本章我们会创建一个类型,该类型会作为以后单元测试的父类型。我们把代码分成一小片一小片的来讲解。
首先,我们来看看该类型的字段:
public class BaseTest { /** 默认的连接URI */ public static final String DEFAULT_URI = "mongodb://localhost:27017"; /** 保存MongoD连接URI的系统属性key */ public static final String MONGODB_URI_SYSTEM_PROPERTY_NAME = "org.mongodb.test.uri"; /** 数据库名 */ private static final String cleanupDB = "mongo-java-driver-test"; private static MongoClientURI mongoClientURI; private static MongoClient staticMongoClient; public Mongo cleanupMongo = null; protected DBCollection collection; }
上面大部分都是我们认识的类型,唯一的DBCollection表示数据库中的一个集合。后面会讲解到。
接下来,看看获取连接URI的代码:
/** * 获取MongoDB的连接URI * @return */ public static synchronized MongoClientURI getMongoClientURI() { if (mongoClientURI == null) { String mongoURIProperty = System.getProperty( MONGODB_URI_SYSTEM_PROPERTY_NAME); String mongoURIString = (mongoURIProperty == null || mongoURIProperty.length() == 0) ? DEFAULT_URI : mongoURIProperty; mongoClientURI = new MongoClientURI(mongoURIString); } return mongoClientURI; }
这段代码应该也非常容易理解,首先是从系统配置的属性中读取连接字符串,如果不存在则使用默认的连接字符串创建URI.
下面,我们来看看建立连接的代码:
/** * 建立连接 */ @BeforeClass public static void testCaseBeforeClass() { if (staticMongoClient == null) { try { staticMongoClient = new MongoClient(getMongoClientURI()); staticMongoClient.dropDatabase(cleanupDB); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { if (staticMongoClient != null) { staticMongoClient.dropDatabase(cleanupDB); staticMongoClient.close(); staticMongoClient = null; } }}); } catch (UnknownHostException e) { throw new RuntimeException(e); } } }
这段代码也不难理解,注意staticMongoClient.dropDatabase用于删除指定名称的数据库。另外注意下Runtime部分的代码,该部分代表程序退出或者终止虚拟机时,会运行addShutdownHook中注册的线程,用于关闭连接。
1.获取数据库
到此,基本代码完成,下面要看看提供给子类使用的方法。
/** * 获取MongoClient * @return */ protected static MongoClient getMongoClient() { return staticMongoClient; } /** * 获取数据库 * @return */ protected static DB getDatabase() { return staticMongoClient.getDB(cleanupDB); }
第一个方法没什么可讲的,第二个方法是重点,在MongoDB Java Driver API中,通过MongoClient的getDB方法,给出数据库名称,就可以得到一个DB对象,该对象就表示MongoDB中的一个数据库,这个对象是我们操作集合的起点。
2.执行adminCommand命令
在MongoDB的shell中,提供了db.adminCommand来执行一些有关的命令。那么,在使用MongoDB Java Driver API时,如何调用adminCommand来执行命令呢。其实非常简单,DB对象提供了一个command的方法,该方法最简单的版本就是接受一个String类型的参数,该参数表名了要执行的命令,command方法会返回一个com.mongodb.CommandResult对象,该对象实际上就是一个HashMap,里面保存了执行命令的结果。实际上就是将BSON格式的结果字符串映射到了HashMap中。
下面的代码,用于判断MongoDB是否大于给定的版本号。
/** * 判断MongoDB的版本号是否大于给定的版本号 * @param version 版本号,必须是1.1,2.1.3.1等的形式 * @return */ protected boolean serverIsAtLeastVersion(double version) { return serverIsAtLeastVersion(version, cleanupMongo); } /** * 判断MongoDB的版本号是否大于给定的版本号 * @param version 版本号,必须是1.1,2.1.3.1等的形式 * @param mongo 一个Mongo对象 * @return */ protected boolean serverIsAtLeastVersion(double version, Mongo mongo) { String serverVersion = (String) mongo.getDB("admin").command("serverStatus").get("version"); return Double.parseDouble(serverVersion.substring(0, 3)) >= version; }
关键是代码mongo.getDB("admin").command("serverStatus").get("version"),为了执行调用adminCommand执行命令,我们需要获取的数据库是admin.上面的代码相当于下面的MongoDB shell
db.serverStatus().version
或
db.adminCommand({"serverStatus":1}).version
接下来,我们继续使用command来实现一些功能。看下面的代码:
/** * 判断是否为单独的服务.即没有使用副本集或者分片 * @param mongo the connection * @return true if connected to a standalone server */ protected static boolean isStandalone(Mongo mongo) { return !isReplicaSet(mongo) && !isSharded(mongo); }
在上面的方法中,分别调用了isReplicaSet和isShaeded两个方法。首先来看isReplicaSet方法,代码如下:
/** * 判断是否使用了副本集 * @param mongo * @return */ protected static boolean isReplicaSet(Mongo mongo) { return runIsMaster(mongo).get("setName") != null; }
在该方法中,最终是去调用runIsMaster方法,该方法会执行"ismaster"命令,获取主服务相关的信息。而setName如果不为空,则表示使用了集群。我们来看看runIsMaster的代码:
/** * 执行isMaster命令,获取master相关信息 * @param mongo * @return */ protected static CommandResult runIsMaster(Mongo mongo) { return mongo.getDB("admin").command(new BasicDBObject("ismaster", 1)); }
BasicDBObject类型目前我们不需要关心,只需要知道它类似一个key/value,command方法需要该对象给出要执行的命令。上面的代码就相当于下面的MongoDB.shell
db.adminCommand({"ismaster":1})
副本集是这样来判断,那么分片又是怎么判断的呢?这就是isSharded方法要做的事情。在MongoDB中,执行
db.adminCommand({"ismaster":1})
获取的BSON结构中,如果使用了分片,会有一个msg字段,该字段的值如果为“isdbgrid”则启用了分片。用java代码操作如下:
/** * 判断是否使用了分片 * @param mongo * @return */ protected static boolean isSharded(Mongo mongo) { CommandResult result = runIsMaster(mongo); Object msg = result.get("msg"); return msg != null && msg.equals("isdbgrid"); }
3.CommandResult
上面我们已经看到了CommandResult的简单使用,本节中,我们稍微更进一步,如果返回的BSON结果中,有嵌套的文档,使用CommandResult如何获取呢?例如下面的field2:
{ field1:xxxx, field2: { field2_1:xxxx, field2_2:xxxx, .... } }
接着1,2中的代码,我们继续完善。假设我们使用了副本集,我需要获取所有副本集中MongoDB节点信息,该如何做呢?在MongoDB shell中,我们可以使用:
db.adminCommand({"replSetGetStatus":1})
在Java中怎么做呢?看下面的方法,该方法遍历副本集中的MongoDB节点,判断与给定的状态字符串是否相等,如果相等,就返回该MongoDB节点的hostName和port:
/** * 获取副本集中主机的hostname和port * @param mongo Mongo对象 * @param stateStrToMatch 副本集中MongoDB节点的状态字符创(primary或者secondary) * @return 主机的hostname和port */ @SuppressWarnings({"unchecked"}) protected String getMemberNameByState(Mongo mongo, String stateStrToMatch) { CommandResult replicaSetStatus = runReplicaSetStatusCommand(mongo); //遍历副本集中的成员 for (final BasicDBObject member : (List<BasicDBObject>) replicaSetStatus.get("members"){ String hostnameAndPort = member.getString("name"); if (!hostnameAndPort.contains(":")) hostnameAndPort = hostnameAndPort + ":27017"; final String stateStr = member.getString("stateStr"); if (stateStr.equalsIgnoreCase(stateStrToMatch)) return hostnameAndPort; } throw new IllegalStateException("No member found in state " + stateStrToMatch); }
runReplicaSetStatusCommand方法下面讲解,我们目前只需要知道它相当于执行了db.adminCommand({"replSetGetStatus":1})命令。关键在于for循环,如果使用了副本集,返回的CommandResult中就会有一个members字段,该字段保存了所有副本集的信息,这些信息体现为一个个BasicDBObject对象。在for循环中,我们遍历每一个副本集成员,注意if (!hostnameAndPort.contains(":")),副本集的"name"字段保存了副本集的hostname和port,形式为host:port,该判断表示的是,如果副本集中的成员的"name"值没有":",则使用的是默认的端口27017.另外,"stateStr"则是副本集的状态,一般是PRIMARY,SECONDARY等值。
接下来时runReplicaSetStatusCommand方法,在讲解该方法之前,我们要啰嗦下db.adminCommand({"replSetGetStatus":1})命令,如果没有使用副本集,则该命令返回的BSON返回BSON如下:
{ "ok" : 0, "errmsg" : "not running with --replSet" }
runReplicaSetStatusCommand就利用了errmsg来决定返回值,代码如下:
protected static CommandResult runReplicaSetStatusCommand(final Mongo mongo) { final CommandResult result = mongo.getDB("admin").command( new BasicDBObject("replSetGetStatus", 1)); String errorMsg = result.getErrorMessage(); if (errorMsg != null && errorMsg.indexOf("--replSet") != -1) { System.err.println("---- SecondaryReadTest: This is not a replica set - not testing secondary reads"); return null; } return result; }
最后是调用getMemberNameByState的两个get方法
/** * 获取primary的hostname和port * @param mongo * @return */ @SuppressWarnings({"unchecked"}) protected String getPrimaryAsString(Mongo mongo) { return getMemberNameByState(mongo, "primary"); } /** * 获取secondary的hostname和port * @param mongo * @return */ @SuppressWarnings({"unchecked"}) protected String getASecondaryAsString(Mongo mongo) { return getMemberNameByState(mongo, "secondary"); }
最后看一个方法,这里不做解释,大家自己看看它是做什么的:
@SuppressWarnings("unchecked") protected int getReplicaSetSize(Mongo mongo) { int size = 0; CommandResult replicaSetStatus = runReplicaSetStatusCommand(mongo); for (final BasicDBObject member : (List<BasicDBObject>) replicaSetStatus.get("members")) { final String stateStr = member.getString("stateStr"); if (stateStr.equals("PRIMARY") || stateStr.equals("SECONDARY")) size++; } return size; }
相关推荐
在Java开发中,与MongoDB的交互通常通过Java驱动程序实现,它提供了对数据库的基本CURD(创建、读取、更新、删除)操作的支持。本篇文章将深入探讨MongoDB在Java环境下的CURD操作,帮助初学者更好地理解和应用。 ...
MongoDB的Java驱动程序是连接Java应用程序与MongoDB服务器的关键组件,它提供了丰富的API来执行各种数据库操作。在本篇文章中,我们将深入探讨`mongodb-driver-core-3.5.0.jar`这一核心驱动包及其相关组件。 `...
mongo-java-driver-3.4.3.jar 是 MongoDB 官方为 Java 开发者提供的 Java 驱动程序的一...这个 JAR 文件包含了与 MongoDB 数据库进行交互所需的类和接口,允许 Java 应用程序连接到 MongoDB 实例并执行各种数据库操作。
MongoDB Java Driver是Java开发者用来与MongoDB数据库交互的官方驱动程序。这个源码依赖库包含了一组Java类和接口,使得开发人员能够方便地在应用程序中执行CRUD(创建、读取、更新、删除)操作以及其他高级功能,如...
总的来说,"mongodb-async-driver-2.0.1.jar"这个包是Java开发者与MongoDB数据库交互的强大工具,它通过异步I/O和事件驱动的编程模型,提高了应用的并发能力和响应速度。通过这个驱动,开发者可以充分利用MongoDB的...
2. `mongodb-driver-3.9.1.jar`: 这是MongoDB Java驱动的主要部分,提供了与MongoDB服务器通信所需的类和接口。它实现了连接管理、命令执行、查询和写入操作等功能。开发者可以使用这个库来创建MongoClient实例,...
MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName="Sameer",Address="8 Gandhi Road")来实现更快的排序。 你可以通过本地或者网络创建数据...
9. **社区与生态**:MongoDB拥有活跃的开发者社区,提供了丰富的驱动程序和集成解决方案,支持各种编程语言,如Python、Java、Node.js等,方便开发者轻松地在应用程序中使用MongoDB。 10. **安全性**:MongoDB ...
MongoDB Java驱动是Java开发者与MongoDB数据库交互的重要工具,它允许Java应用程序通过标准的Java API来执行查询、插入、更新和删除等操作。在Java中使用MongoDB,首先需要安装并配置对应的驱动版本,以确保与正在...
驱动程序支持连接管理、查询构建、数据序列化和异步操作等功能,使得Java应用能够无缝地存取MongoDB数据库。 总结来说,MongoDB是一个强大的NoSQL数据库,MongoDB Compass是其配套的可视化工具,而这个压缩包则提供...
10. **操作工具**:MongoDB提供了命令行工具,如mongo shell,用于交互式地操作数据库,以及mongod、mongos等用于数据库服务的启动和管理。 在解压“mongodb-win32-i386-2.2.6.zip”后,你会得到一系列的文件和目录...
Java驱动是MongoDB官方提供的一个用于Java应用的API,它允许开发者通过编写Java代码来操作MongoDB数据库。主要包含以下核心组件: 1. MongoClient:这是连接到MongoDB服务器的主入口点,用于建立与MongoDB实例的...
与传统的关系型数据库不同,MongoDB不使用表格和行/列的结构,而是采用集合、文档、字段的模型,其中文档是JSON格式的数据,这使得数据存储更加灵活。 在“mongodb-win32-x86_64”这个标题中,我们可以推断这是...
此外,还可以利用各种语言的驱动程序(如Python、Java、Node.js等)在应用程序中连接和操作MongoDB数据库。 总的来说,MongoDB-win32-x86_64-2008plus-ssl-3.2.10-signed.zip是一个针对Windows环境的、包含SSL加密...
MongoDB是一个流行的开源、分布式...总的来说,这些jar文件构成了Java开发者与MongoDB数据库交互的基础框架,提供了完整的API来执行各种数据库操作。理解并熟练使用这些组件,对于在Java应用中集成MongoDB至关重要。
本篇将详细介绍如何利用Java实现MongoDB数据库的增、删、改、查(CRUD)操作。 1. **连接MongoDB** 要使用Java连接MongoDB,首先需要引入MongoDB Java驱动程序的依赖。在Maven项目中,可以在pom.xml文件中添加以下...
`CacheServiceImp.java`可能是一个实现了缓存服务的类,它可以与MongoDB连接池协同工作,将经常访问的数据存储在内存中,进一步减少对数据库的访问。缓存策略可以显著提升应用性能,尤其是对于读密集型的应用。 `...
在实际应用中,MongoDB通常与各种编程语言结合使用,如Python、Java、Node.js、C#等,通过官方提供的驱动程序进行连接和操作。这些驱动程序提供了易于使用的API,简化了开发过程。 总的来说,MongoDB因其灵活性、可...
为了方便开发者使用 Java 进行开发,MongoDB 提供了官方的 Java 驱动程序(MongoDB Java Driver),使得 Java 应用能够轻松地与 MongoDB 数据库进行交互。 #### 二、基本概念与连接 在开始使用 MongoDB Java Driver...
Spring Data MongoDB 是 Spring 框架中的一个模块,专门用于简化与 MongoDB 数据库的交互。MongoDB 是一个流行的分布式文档数据库,以其灵活性和高性能而受到开发者们的青睐。Spring Data MongoDB 提供了高级抽象,...