`

MongoDB与Java(2) - 操作数据库

阅读更多

我们知道,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;
    }

 

 

 

分享到:
评论

相关推荐

    mongoDB-CURD操作-----JAVA

    mongoDB-CURD操作-----JAVA 对初学入门还是有点用处滴!

    mongodb-win32-x86_64-2008plus-ssl-v3.4-latest-signed.msi

    MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName="Sameer",Address="8 Gandhi Road")来实现更快的排序。 你可以通过本地或者网络创建数据...

    Mongodb数据库JAVA操作例子

    Mongodb 数据库 JAVA 增删改查操作例子

    Mongodb java包

    java用来链接Mongo数据库所需要的jar mongodb-driver-3.6.0.jar bson-3.6.0.jar mongodb-driver-core-3.6.0.jar

    真实可用的mongodb下周地址.txt

    视频目录: 01-mongodb文档型数据库特点介绍 01-NoSQL简介 02-mongodb安装过程 02-mongodb操作1 03-mongodb操作2 ...03-mongo库表操作语句 ...04-CURD操作详解 ...04-mongodb操作3 ...12-使用java操作mongodb

    mongodb-compass-community-1.16.4-win32-x64.zip

    MongoDB的讲义,资源包。与大数据hadoop学习相关,包含快速入手MongoDB和MongoDB集群安全两个部分,以及mongoDB的可视化工具zip包MongoDB-compass

    mongodb-driver-3.2.1.jar

    java链接mongodb数据库驱动

    java实现mongodb数据库的操作

    内部资料,mongodb的存储检索等。完整程序代码封装

    mongodb-windows-x86_64-4.4.6-signed.zip

    mongodb安装包 解压后直接安装使用即可

    通过java向mongodb中插入数据

    使用java向mongodb中插入数据 一、Linux安装mongodb 二、MongoDB客户端工具(MongoVUE)访问mongodb 三、通过Java操作MongoDB

    MongoDB-Java驱动API

    此文档专门针对于使用Java语言操作MongoDB数据库的开发人员。

    mongoDB java 驱动

    在开发中使用 java ,数据库使用mongodb则mongodb-java-driver 是不可少的,本人亲自试过可以使用!

    QxOrm-Source 数据库操作库

    1、QxOrm-Source 数据库操作库源码 2、QxOrm 是一个C++库,旨在为C++用户提供对象关系映射 (ORM)功能。 QxOrm由Lionel Marty开发,他自2003年以来一直担任软件开发工程师 基于每个类的简单C++设置函数(如Java中...

    【MongoDB for Java】Java操作MongoDB数据库

    本篇文章现在我们就用Java来操作MongoDB的数据。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    mongodb-driver-3.1.0

    mobgodb 数据驱动java版

    module-database-mongodb:MongoDB 的 Core9 数据库模块

    模块-数据库-mongodb 该模块包含 MongoDB 的数据库模块。

    mongodb-trigger:mongodb事件触发器

    mongodb-trigger类似关系数据库的触发器,mongodb-trigger同样可以监听操作事件,粒度可以达到字段级别。使用场景同步mongodb数据到异构存储,如:mongo -&gt; elasticsearch业务cache刷新,如:redis中镜像数据监听数据...

    mongodb-win32-i386-1.2.1

    MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 它的特点是高性能、易部署、易使用,存储数据非常方便。 主要功能特性有: 面向集合存储,易存储...

    java操作MongoDB数据库代码实例

    该rar包中包括MOngoDB数据库操作基本的增删改查,以及在CMD命令行中怎么配置MOngodb和增删改查,还有就是连接mongoDB的jar包和详细的操作文档,本来想上传NOde.js来着,可是只能上传60兆,只能放弃了,不过这些已经...

    Java操作MongoDB数据库示例分享

    MongoDB是一个文档型数据库,是NOSQL家族中最重要的成员之一,以下代码封装了MongoDB的基本操作。 MongoDBConfig.java package com.posoftframework.mongodb; import java.io.File; import java.io.FileInputStream...

Global site tag (gtag.js) - Google Analytics