MongoClient - smile0821/learngit GitHub Wiki

网上关于MongoDB Java Driver API的知识点都非常零散,自己在使用的过程中,总是遇到很多问题,也是一点点的实验,一点点的查,或者看下源码。在这一系列的博客中,就把自己学到的总结一下,所学较浅,错误难免,希望得到大家的指正。

本系列的文章的源码大部分会使用mongo-java-driver中的单元测试的源代码,里面对每个API的示例都比较详细,大家可以去Git或者网络上搜一搜。

本章讨论以下问题

  1. 如何在Java程序中与MongoDB建立连接

  2. 如何与副本集建立连接

  3. 如何使用连接池

1.1 建立连接

在MongoDB Java Driver API中,要操作MongoDB的第一步和使用其他DB Java Driver类似,都需要首先和数据库建立连接。在MongoDBJava Driver API中,建立连接的类为com.mongodb.MongoClient.在讨论连接字符串等内容之前,我们来看看它最简单的使用方式:

Java代码 收藏代码 MongoClient client = new MongoClient();
一个构造函数不带任何参数的版本。使用这个构造函数连接到的是本地的MongoDB服务,即/127.0.0.1:27017,当然你如果改变了MongoDB服务的端口,那么这里显示的端口就是你的端口了。

我们可以通过以下单元测试代码进行验证:

Java代码 收藏代码 @Test
public void testConstruactors() throws UnknownHostException {
MongoClient client;

client = new MongoClient();  
assertEquals(new ServerAddress(), client.getAddress());  
client.close();  

}
目前不需要关心ServerAddress类型,它主要作用于MongoDB服务相关的信息。注意,跟其他DB Java Driver一样,记得关闭连接。 当然,我们也可以指定连接的Host,看下面的单元测试: Java代码 收藏代码 client = new MongoClient("127.0.0.1");
assertEquals(new ServerAddress("127.0.0.1"), client.getAddress());
client.close();
这里,我指定的是本机,你可以使用任何有效的IP. 2.2 设置连接的各项属性 和其他DB Java Driver的连接一样,MongoDB Java Driver的连接也提供了很多属性,我们来了解其中几个。 要设置MongoClient有关连接的属性,我们需要用到com.mongodb.MongoClientOpations类。这个类包含了 MongoClient建立连接时,与连接相关的所有属性。该类提供了一Builder模式的方式创建并设置这些属性的值。 Java代码 收藏代码 MongoClientOptions customClientOptions =
new MongoClientOptions.Builder().connectionsPerHost(50).build();
分析下上面的代码,MongoClientOptions.Builder()得到的是一个MongoClientOptions的Builder,通过该Builder可以设置各种Options,例如connectionsPerHost(50),设置连接池中连接个数,需要注意的是,每个属性的设置方法的返回类型是一个Builder,这意味着我们可以采用类似下面的链式调用: Java代码 收藏代码 MongoClientOptions customClientOptions =
new MongoClientOptions.Builder().connectionsPerHost(50).maxWaitTime(2000).build()
最后,当我们将需要的各项值设定好后,就调用Builder的builder()方法,得到一个MongoClientOptions对象。 问题来了,上面的代码只是为各项连接相关的属性赋值,那如何将这些值交给MongoClient,让它按照我们给出的属性值来建立连接呢? 答案就是MongoClient的构造函数,看下面的代码: Java代码 收藏代码 MongoClientOptions customClientOptions =
new MongoClientOptions.Builder()
.connectionsPerHost(50)
.maxWaitTime(2000).build();
MongoOptions options = new MongoOptions(customClientOptions);
client = new MongoClient("127.0.0.1", customClientOptions);
assertEquals(new ServerAddress("127.0.0.1"), client.getAddress());
assertEquals(options, client.getMongoOptions());
client.close();
MongoOptions options = new MongoOptions(customClientOptions);这句代码并不影响MongoClientOptions的使用,只是展示如何获取到我们设置的MongoClientOptions,另外,我们也可以直接通过MongoClient.getMongoOptions()获取到MongoOptions后,进行设置,而不使用MongoClientOptions,如下: Java代码 收藏代码 MongoOptions mps = mongoClient.getMongoOptions();
mps.setConnectionsPerHost(mongoDBConfig.getPoolSize());
mps.setConnectTimeout(mongoDBConfig.getConnectTimeout());
mps.setMaxWaitTime(mongoDBConfig.getMaxWaitTime());
不过我推荐MongoClientOptions,代码更加优雅。另外,即使我们没有设置MongoClientOptions,MongoClient也会有默认的设置,大家可以自己把他们打印出来看看。

1.3 使用连接字符串进行连接 上面的连接只是指定了连接到MongoDB的服务,但是具体连接到哪个数据库呢?使用什么样的登录名和密码呢?这个时候就用到连接字符串了,我们先解释下MongoDB的连接字符串,如下: Java代码 收藏代码 mongodb://user1:[email protected]/test?authMechanism=MONGODB-CR&maxPoolSize=500
上面的连接字符串模式如下: mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]] 大家可以看到,大部分内容是可选的,也就是说,最简单的连接字符串就是

mongodb://127.0.0.1

当然,真正在项目中,没人会这么用。

我们发现了一个有趣的地方,就是可以提供多个host和port.这是因为,我们使用MongoDB,会以集群的方式使用, 集群中一台主服务,多个从服务,这个时候,我们就要在连接字符串中列出来,例如:

Java代码 收藏代码 mongodb://host1,host2,host3/?connect=direct;slaveOk=true
MongoDB的连接字符串就简单介绍到这里,不了解的童鞋可以去http://www.w3cschool.cc/mongodb/mongodb-connections.html看看。

回到主题,在MongoClient中,如何使用连接字符串进行连接呢?MongoDB Java Driver提供了一个com.mongodb.MongoClientURI类型,使用方式如下:

Java代码 收藏代码 client = new MongoClient(
new MongoClientURI(
"mongodb://kwiner:[email protected]/test?authMechanism=MONGODB-CR&maxPoolSize=500"));
client.close();

1.4 Mongo和MongoClient的关系

MongoClient继承自Mongo,使用Mongo也可建立连接,但是需要使用与Mongo适应的MongoOptions,MongoURI等类型。

1.5 安全连接

MongoClient也提供了使用用户名和密码连接到指定数据库的方式,需要用到com.mongodb.MongoCredential,该类在mongo-java-driver的2.11.0版本中才开始提供,请大家注意。

Java代码 收藏代码 MongoClientOptions clientOptions =
new MongoClientOptions.Builder()
.connectionsPerHost(50)
.maxWaitTime(2000).build();
List lstCredentials =
Arrays.asList(MongoCredential.createMongoCRCredential(
"admin", "myinfo", "123456".toCharArray()));
client = new MongoClient(new ServerAddress("127.0.0.1"),lstCredentials, clientOptions);
client.close();
首先注意List lstCredentials = Arrays.asList(MongoCredential.createMongoCRCredential("admin", "myinfo", "123456".toCharArray()));这一句代码,使用了MongoCredential的静态方法createMongoCRCredential创建MongoCredential,createMongoCRCredential会创建使用通用安全服务应用程序接口来完全的访问MongoDB.另外,因为MongoClient要求一个List ,所以我们这里使用了Arrays.asList。使用createMongoCRCredential创建MongoCredential,需要提供username,database和password. 1.6 连接池 MongoClient本身就使用了连接池,如果我们使用了MongoClientOptions,则默认是100个连接 Java代码 收藏代码 MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
MongoClientOptions options = builder.build();
assertEquals(100, options.getConnectionsPerHost());//最大连接数
assertEquals(0, options.getMinConnectionsPerHost());//最小连接数
assertEquals(0, options.getMaxConnectionIdleTime());//连接的最大闲置时间
assertEquals(0, options.getMaxConnectionLifeTime());//连接的最大生存时间
assertEquals(120000, options.getMaxWaitTime());//最大等待可用连接的时间
assertEquals(10000, options.getConnectTimeout());//连接超时时间

MongoClient client = new MongoClient("127.0.0.1", customClientOptions);
client.close();
其中闲置时间和生存时间为0,表示无限制。 最后,MongoClient的close方法会关闭底层连接,MongoClient的实例将变得不可用,我们应该根据程序的需要,适当的调用该方法,释放资源。 1.7 连接副本集

使用MongoDB作为数据库,基本上都会使用副本集,在这个集里面,有primary节点,又有其他secondary节点,并使用了读写分离,这个时候,使用java连接MongoDB服务应该怎么做呢? 其实很简单,就是使用一个ServerAddress集合保存副本集中的所有节点,然后作为MongoClient的构造函数的参数,并使用ReadPreference设置读写策略,注意,ReadPreference的读写策略既可以在MongoClient上设置,作用与使用MongoClient连接的所有操作,也可以设置到每次具体的集合操作上,作用域该次操作。代码如下:

在MongoClient上设置读写策略:

Java代码 收藏代码 List addresses = new ArrayList();
ServerAddress address1 = new ServerAddress("192.168.1.136" , 27017);
ServerAddress address2 = new ServerAddress("192.168.1.137" , 27017);
ServerAddress address3 = new ServerAddress("192.168.1.138" , 27017);
addresses.add(address1);
addresses.add(address2);
addresses.add(address3);

mongoClient = new MongoClient(lstAddrs);
mongoClient.setReadPreference(ReadPreference.primary());
某次操作上设置读写策略

Java代码 收藏代码 List addresses = new ArrayList();
ServerAddress address1 = new ServerAddress("192.168.1.136" , 27017);
ServerAddress address2 = new ServerAddress("192.168.1.137" , 27017);
ServerAddress address3 = new ServerAddress("192.168.1.138" , 27017);
addresses.add(address1);
addresses.add(address2);
addresses.add(address3);

MongoClient client = new MongoClient(addresses);
DB db = client.getDB( "test" );
DBCollection coll = db.getCollection( "test" );

BasicDBObject object = new BasicDBObject();
object.append( "test2" , "testval2" );

//读操作从副本节点读取
ReadPreference preference = ReadPreference. secondary();
DBObject dbObject = coll.findOne(object, null , preference);
System. out .println(dbObject);

Mongo的实例其实就是一个数据库连接池,这个连接池里默认有10个链接。我们没有必要重新实现这个链接池,但是我们可以更改这个连接池的配置。因为Mongo的实例就是一个连接池,所以,项目中最好只存在一个Mongo的实例。

常见的配置参数:

connectionsPerHost:每个主机的连接数

threadsAllowedToBlockForConnectionMultiplier:线程队列数,它以上面connectionsPerHost值相乘的结果就是线程队列最大值。如果连接线程排满了队列就会抛出“Out of semaphores to get db”错误。

maxWaitTime:最大等待连接的线程阻塞时间

connectTimeout:连接超时的毫秒。0是默认和无限

socketTimeout:socket超时。0是默认和无限

autoConnectRetry:这个控制是否在一个连接时,系统会自动重试

还有许多配置,可以参见mongodb的API。

下面看代码:

[java] view plaincopy在CODE上查看代码片派生到我的代码片

package com.mongo.common;

import java.net.UnknownHostException;

import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.MongoOptions;

public class MongoManager {
private final static String HOST = "localhost";// 端口
private final static int PORT = 27017;// 端口
private final static int POOLSIZE = 100;// 连接数量
private final static int BLOCKSIZE = 100; // 等待队列长度
private static Mongo mongo = null;

private MongoManager() { }  

static {  
    initDBPrompties();  
}  

public static DB getDB(String dbName) {  
    return mongo.getDB(dbName);  
}  

/** 
 * 初始化连接池 
 */  
private static void initDBPrompties() {  
    // 其他参数根据实际情况进行添加  
    try {  
        mongo = new Mongo(HOST, PORT);  
        MongoOptions opt = mongo.getMongoOptions();  
        opt.connectionsPerHost = POOLSIZE;  
        opt.threadsAllowedToBlockForConnectionMultiplier = BLOCKSIZE;  
    } catch (UnknownHostException e) {  
    } catch (MongoException e) {  

    }  

}  

}

使用的时候,如下所示:

[java] view plaincopy在CODE上查看代码片派生到我的代码片

/** * 保存 *
* @param user * @throws UnknownHostException */
public void save(User user) throws UnknownHostException {
DB myMongo = MongoManager.getDB("myMongo");
DBCollection userCollection = myMongo.getCollection("user");

    DBObject dbo = (DBObject) JSON.parse(user.toJson());  
    userCollection.insert(dbo);  
}  
  /** 
      * 项目名:SpiderCrawler 
      * 文件名:MongoDBDao.java 
      * 作者:zhouyh 
      * 时间:2014-8-30 下午03:46:55 
      * 描述:TODO(用一句话描述该文件做什么)  
      */  
    package com.newsTest.dao;  

    import java.util.ArrayList;  

    import com.mongodb.DB;  
    import com.mongodb.DBCollection;  
    import com.mongodb.DBObject;  

    /** 
     * 类名: MongoDBDao 
     * 包名: com.newsTest.dao 
     * 作者: zhouyh 
     * 时间: 2014-8-30 下午03:46:55 
     * 描述: TODO(这里用一句话描述这个类的作用)  
     */  
    public interface MongoDBDao {  
        /** 
         *  
         * 方法名:getDb 
         * 作者:zhouyh 
         * 创建时间:2014-8-30 下午03:53:40 
         * 描述:获取指定的mongodb数据库 
         * @param dbName 
         * @return 
         */  
        public DB getDb(String dbName);  
        /** 
         *  
         * 方法名:getCollection 
         * 作者:zhouyh 
         * 创建时间:2014-8-30 下午03:54:43 
         * 描述:获取指定mongodb数据库的collection集合 
         * @param dbName    数据库名 
         * @param collectionName    数据库集合 
         * @return 
         */  
        public DBCollection getCollection(String dbName, String collectionName);  
        /** 
         *  
         * 方法名:inSert 
         * 作者:zhouyh 
         * 创建时间:2014-8-30 下午04:07:35 
         * 描述:向指定的数据库中添加给定的keys和相应的values 
         * @param dbName 
         * @param collectionName 
         * @param keys 
         * @param values 
         * @return 
         */  
        public boolean inSert(String dbName, String collectionName, String[] keys, Object[] values);  
        /** 
         *  
         * 方法名:delete 
         * 作者:zhouyh 
         * 创建时间:2014-8-30 下午04:09:00 
         * 描述:删除数据库dbName中,指定keys和相应values的值 
         * @param dbName 
         * @param collectionName 
         * @param keys 
         * @param values 
         * @return 
         */  
        public boolean delete(String dbName, String collectionName, String[] keys, Object[] values);  
        /** 
         *  
         * 方法名:find 
         * 作者:zhouyh 
         * 创建时间:2014-8-30 下午04:11:11 
         * 描述:从数据库dbName中查找指定keys和相应values的值 
         * @param dbName 
         * @param collectionName 
         * @param keys 
         * @param values 
         * @param num 
         * @return 
         */  
        public ArrayList<DBObject> find(String dbName, String collectionName, String[] keys, Object[] values, int num);  
        /** 
         *  
         * 方法名:update 
         * 作者:zhouyh 
         * 创建时间:2014-8-30 下午04:17:54 
         * 描述:更新数据库dbName,用指定的newValue更新oldValue 
         * @param dbName 
         * @param collectionName 
         * @param oldValue 
         * @param newValue 
         * @return 
         */  
        public boolean update(String dbName, String collectionName, DBObject oldValue, DBObject newValue);  
        /** 
         *  
         * 方法名:isExit 
         * 作者:zhouyh 
         * 创建时间:2014-8-30 下午04:19:21 
         * 描述:判断给定的keys和相应的values在指定的dbName的collectionName集合中是否存在 
         * @param dbName 
         * @param collectionName 
         * @param keys 
         * @param values 
         * @return 
         */  
        public boolean isExit(String dbName, String collectionName, String key, Object value);  

    } 
/**
  * 项目名:SpiderCrawler
  * 文件名:MongoDBDaoImpl.java
  * 作者:zhouyh
  * 时间:2014-8-30 下午04:21:11
  * 描述:TODO(用一句话描述该文件做什么) 
  */
package com.newsTest.dao.impl;

import java.net.UnknownHostException;
import java.util.ArrayList;

import com.newsTest.dao.MongoDBDao;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoException;
import com.mongodb.WriteResult;

/**
 * 类名: MongoDBDaoImpl
 * 包名: com.newsTest.dao.impl
 * 作者: zhouyh
 * 时间: 2014-8-30 下午04:21:11
 * 描述: TODO(这里用一句话描述这个类的作用) 
 */
public class MongoDBDaoImpl implements MongoDBDao{

    /**
     * MongoClient的实例代表数据库连接池,是线程安全的,可以被多线程共享,客户端在多线程条件下仅维持一个实例即可
     * Mongo是非线程安全的,目前mongodb API中已经建议用MongoClient替代Mongo
     */
    private MongoClient mongoClient = null;
    /**
     * 
     * 私有的构造函数
     * 作者:zhouyh
     */
    private MongoDBDaoImpl(){
        if(mongoClient == null){
            MongoClientOptions.Builder build = new MongoClientOptions.Builder();        
            build.connectionsPerHost(50);   //与目标数据库能够建立的最大connection数量为50
            build.autoConnectRetry(true);   //自动重连数据库启动
            build.threadsAllowedToBlockForConnectionMultiplier(50); //如果当前所有的connection都在使用中,则每个connection上可以有50个线程排队等待
            /*
             * 一个线程访问数据库的时候,在成功获取到一个可用数据库连接之前的最长等待时间为2分钟
             * 这里比较危险,如果超过maxWaitTime都没有获取到这个连接的话,该线程就会抛出Exception
             * 故这里设置的maxWaitTime应该足够大,以免由于排队线程过多造成的数据库访问失败
             */
            build.maxWaitTime(1000*60*2);
            build.connectTimeout(1000*60*1);    //与数据库建立连接的timeout设置为1分钟

            MongoClientOptions myOptions = build.build();       
            try {
                //数据库连接实例
                mongoClient = new MongoClient("127.0.0.1", myOptions);          
            } catch (UnknownHostException e) {
                // TODO 这里写异常处理的代码
                e.printStackTrace();
            } catch (MongoException e){
                e.printStackTrace();
            }

        }
    }

    /********单例模式声明开始,采用饿汉式方式生成,保证线程安全********************/

    //类初始化时,自行实例化,饿汉式单例模式
    private static final MongoDBDaoImpl mongoDBDaoImpl = new MongoDBDaoImpl();
    /**
     * 
     * 方法名:getMongoDBDaoImplInstance
     * 作者:zhouyh
     * 创建时间:2014-8-30 下午04:29:26
     * 描述:单例的静态工厂方法
     * @return
     */
    public static MongoDBDaoImpl getMongoDBDaoImplInstance(){
        return mongoDBDaoImpl;
    }

    /************************单例模式声明结束*************************************/

    @Override
    public boolean delete(String dbName, String collectionName, String[] keys,
            Object[] values) {
        DB db = null;
        DBCollection dbCollection = null;
        if(keys!=null && values!=null){
            if(keys.length != values.length){   //如果keys和values不对等,直接返回false
                return false;
            }else{
                try {
                    db = mongoClient.getDB(dbName); //获取指定的数据库
                    dbCollection = db.getCollection(collectionName);    //获取指定的collectionName集合

                    BasicDBObject doc = new BasicDBObject();    //构建删除条件
                    WriteResult result = null;  //删除返回结果
                    String resultString = null;

                    for(int i=0; i<keys.length; i++){
                        doc.put(keys[i], values[i]);    //添加删除的条件
                    }
                    result = dbCollection.remove(doc);  //执行删除操作

                    resultString = result.getError();

                    if(null != db){
                        try {
                            db.requestDone();   //请求结束后关闭db
                            db = null;
                        } catch (Exception e) {
                            // TODO: handle exception
                            e.printStackTrace();
                        }

                    }

                    return (resultString!=null) ? false : true; //根据删除执行结果进行判断后返回结果
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                } finally{
                    if(null != db){
                        db.requestDone();   //关闭db
                        db = null;
                    }
                }

            }
        }
        return false;
    }

    @Override
    public ArrayList<DBObject> find(String dbName, String collectionName,
            String[] keys, Object[] values, int num) {
        ArrayList<DBObject> resultList = new ArrayList<DBObject>(); //创建返回的结果集
        DB db = null;
        DBCollection dbCollection = null;
        DBCursor cursor = null;
        if(keys!=null && values!=null){
            if(keys.length != values.length){
                return resultList;  //如果传来的查询参数对不对,直接返回空的结果集
            }else{
                try {
                    db = mongoClient.getDB(dbName); //获取数据库实例
                    dbCollection = db.getCollection(collectionName);    //获取数据库中指定的collection集合

                    BasicDBObject queryObj = new BasicDBObject();   //构建查询条件

                    for(int i=0; i<keys.length; i++){   //填充查询条件
                        queryObj.put(keys[i], values[i]);
                    }               
                    cursor = dbCollection.find(queryObj);   //查询获取数据
                    int count = 0;
                    if(num != -1){  //判断是否是返回全部数据,num=-1返回查询全部数据,num!=-1则返回指定的num数据
                        while(count<num && cursor.hasNext()){
                            resultList.add(cursor.next());
                            count++;
                        }
                        return resultList;
                    }else{
                        while(cursor.hasNext()){
                            resultList.add(cursor.next());
                        }
                        return resultList;
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                } finally{              
                    if(null != cursor){
                        cursor.close();
                    }
                    if(null != db){
                        db.requestDone();   //关闭数据库请求
                    }
                }
            }
        }

        return resultList;
    }

    @Override
    public DBCollection getCollection(String dbName, String collectionName) {
        // TODO Auto-generated method stub
        return mongoClient.getDB(dbName).getCollection(collectionName);
    }

    @Override
    public DB getDb(String dbName) {
        // TODO Auto-generated method stub
        return mongoClient.getDB(dbName);
    }

    @Override
    public boolean inSert(String dbName, String collectionName, String[] keys,
            Object[] values) {
        DB db = null;
        DBCollection dbCollection = null;
        WriteResult result = null;
        String resultString = null;
        if(keys!=null && values!=null){
            if(keys.length != values.length){
                return false;
            }else{
                db = mongoClient.getDB(dbName); //获取数据库实例
                dbCollection = db.getCollection(collectionName);    //获取数据库中指定的collection集合
                BasicDBObject insertObj = new BasicDBObject();
                for(int i=0; i<keys.length; i++){   //构建添加条件
                    insertObj.put(keys[i], values[i]);
                }

                try {
                    result = dbCollection.insert(insertObj);
                    resultString = result.getError();
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }finally{
                    if(null != db){
                        db.requestDone();   //请求结束后关闭db
                    }
                }               
                return (resultString != null) ? false : true;
            }
        }
        return false;
    }

    @Override
    public boolean isExit(String dbName, String collectionName, String key,
            Object value) {
        // TODO Auto-generated method stub
        DB db = null;
        DBCollection dbCollection = null;
        if(key!=null && value!=null){
            try {
                db = mongoClient.getDB(dbName); //获取数据库实例
                dbCollection = db.getCollection(collectionName);    //获取数据库中指定的collection集合
                BasicDBObject obj = new BasicDBObject();    //构建查询条件
                obj.put(key, value);

                if(dbCollection.count(obj) > 0) {
                    return true;
                }else{
                    return false;
                }
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            } finally{
                if(null != db){
                    db.requestDone();   //关闭db
                    db = null;
                }
            }

        }
        return false;
    }

    @Override
    public boolean update(String dbName, String collectionName,
            DBObject oldValue, DBObject newValue) {
        DB db = null;
        DBCollection dbCollection = null;
        WriteResult result = null;
        String resultString = null;

        if(oldValue.equals(newValue)){
            return true;
        }else{
            try {
                db = mongoClient.getDB(dbName); //获取数据库实例
                dbCollection = db.getCollection(collectionName);    //获取数据库中指定的collection集合

                result = dbCollection.update(oldValue, newValue);
                resultString = result.getError();

                return (resultString!=null) ? false : true;
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            } finally{
                if(null != db){
                    db.requestDone();   //关闭db
                    db = null;
                }
            }

        }

        return false;
    }

    /**
     * 方法名:main
     * 作者:zhouyh
     * 创建时间:2014-8-30 下午04:21:11
     * 描述:TODO(这里用一句话描述这个方法的作用)
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

}

带关闭连接

public enum MongoUtil {

	instance;

	private static MongoClient mongoClient;

	static{

		String ip = "127.0.0.1";

		int port = 27017;

		instance.mongoClient = new MongoClient(ip, port);

		//安全验证(可选)

//		boolean auth = db.authenticate(userName, pssword);

		Builder options = new MongoClientOptions.Builder();

		options.cursorFinalizerEnabled(true);

		options.connectionsPerHost(300); //连接池数量(默认100)

		options.connectTimeout(30000); //链接超时 

		options.maxWaitTime(5000);

		options.socketTimeout(0); //套接字超时时间, 0无限制

		options.threadsAllowedToBlockForConnectionMultiplier(5000); //线程队列数量,满了会抛出“Out of semaphores to get db”异常

		options.writeConcern(WriteConcern.SAFE);

		options.build();

	}

	/**

	 * 获取database

	 * @param dbName

	 * @return

	 */

	public MongoDatabase getDB(String dbName){

		if (dbName != null && !"".equals(dbName)) {

			MongoDatabase database = mongoClient.getDatabase(dbName);

			return database;

		}

		return null;

	}

	/**

	 * 获取collection 

	 * @param dbName

	 * @param collName

	 * @return

	 */

	public MongoCollection<Document> getCollection(String dbName, String collName){

		if (null == collName || "".equals(collName)) {

			return null;

		}

		if (null == dbName || "".equals(dbName)) {

			return null;

		}

		MongoDatabase database = mongoClient.getDatabase(dbName);

		if (database != null) {

			MongoCollection<Document> collection = database.getCollection(collName);

			return collection;

		}else{

			return null;

		}

	}

	/**

	 * 获取某DB下所有表名

	 * @param dbName

	 * @return

	 */

	public List<String> getAllCollections(String dbName){

		MongoIterable<String> colls = getDB(dbName).listCollectionNames();

		List<String> result = new ArrayList<String>();

		for(String string : colls){

			result.add(string);

		}

		return result;

	}

	/**

	 * 获取所有数据库名

	 * @return

	 */

	public List<String> getAllDBNames(){

		MongoIterable<String> dbs = mongoClient.listDatabaseNames();

		List<String> result = new ArrayList<String>();

		for (String string : dbs){

			result.add(string);

		}

		return result;

	}

	/**

	 * 删除一个数据库

	 * @param dbName

	 */

	public void dropDB(String dbName){

		getDB(dbName).drop();

	}

	/**

	 * 根据_id查询对象

	 * @param collection

	 * @param id

	 * @return

	 */

	public Document findById(MongoCollection<Document> collection, Long id){

		Document document = collection.find(Filters.eq("_id", id)).first();

		return document;

	}

	/**

	 * 查询一个collection下记录数量

	 * @param collection

	 * @return

	 */

	public int getCount(MongoCollection<Document> collection) {

		int count = (int) collection.count();

		return count;

	}

	/**

	 * 条件查询

	 * @param collection

	 * @param filter

	 * @return

	 */

	public MongoCursor<Document> find(MongoCollection<Document> collection, Bson filter){

		return collection.find(filter).iterator();

	}

	/**

	 * 分页查询

	 * @param collection

	 * @param filter

	 * @param pageNo

	 * @param pageSize

	 * @return

	 */

	public MongoCursor<Document> findByPage(MongoCollection<Document> collection, Bson filter, int pageNo, int pageSize) {

		Bson orderBy = new BasicDBObject("_id", 1);

		return collection.find(filter).sort(orderBy).skip((pageNo - 1) * pageSize).limit(pageSize).iterator();

	}

	/**

	 * 通过id删除

	 * @param collection

	 * @param id

	 * @return

	 */

	public int deleteById(MongoCollection<Document> collection, Long id){

		int count = 0;

		Bson filter = Filters.eq("_id", id);

		DeleteResult deleteResult = collection.deleteOne(filter);

		count = (int) deleteResult.getDeletedCount();

		return count;

	}

	/**

	 * 更新

	 * @param collection

	 * @param id

	 * @param newDoc

	 * @return

	 */

	public Document updateById(MongoCollection<Document> collection, Long id, Document newDoc){

		Bson filter = Filters.eq("_id", id);

//		collection.replaceOne(filter, newDoc);//完全替换

		collection.updateOne(filter, new Document("$set", newDoc));

		return newDoc;

	}

	/**

	 * 关闭连接(确定当前进程不会再使用该连接才使用,否则会报错)

	 * 实际情况下并不需要调取该方法

	 * 当该进程结束后会自动释放连接

	 * (当前是在catch中调用此方法,如果报错,尝试注掉catch中的语句)

	 */

	public void close(){

		if (mongoClient != null) {

			mongoClient.close();

			mongoClient = null;

		}

	}

}
⚠️ **GitHub.com Fallback** ⚠️