MongoDB的连接池和连接管理


  • Lv 1

    在关系型数据库中,我们总是需要关闭使用的数据库连接,不然大量的创建连接会导致资源的浪费甚至于数据库宕机。这篇文章主要想解释一下mongoDB的连接池以及连接管理机制,如果正对此有疑惑的朋友可以看一下。

    通常我们习惯于new 一个connection并且通常在finally语句中调用connection的close()方法将其关闭。正巧,mongoDB中当我们new一个Mongo的时候,会发现它也有一个close()方法。所以会出现这样的情况:我们在需要DB操作的方法中new一个mongo实例,然后调用mongo.getDB()方法拿到对应的连接,操作完数据之后再调用mongo.close()方法来关闭连接。 看起来貌似是没有什么问题,但是如果你再研究一下mongo的API,你会发现这样耳朵操作就相当于园丁在浇花的时候去打了一桶水,然后舀了一勺水浇一朵花,然后他把一桶水全倒了回去,重新打一桶水,再舀了一勺水浇另外一朵花。。。

    说到这里大家应该都已经明白了,其实当你new Mongo()的时候,就创建了一个连接池,getDB()只是从这个连接池中拿一个可用的连接。而连接池是不需要我们及时关闭的,我们可以在程序的生命周期中维护一个这样的单例,至于从连接池中拿出的连接,我们需要关闭吗?答案是NO。你会发现DB根本没有close()之类的方法。在mongoDB中,一个连接池会维持一定数目的连接,当你需要的时候调用getDB()去连接池中拿到连接,而mongo会在这个DB执行完数据操作时候自动收回连接到连接池中待用。所以在mongoDB中大家不必担心连接没有关闭的问题,在你需要在所有操作结束或者整个程序shutdown的时候调用mongo的close()方法即可。

    以下的官网的一些解释:

    public Class Mongo:

    A database connection with internal connection pooling. For most applications, you should have one Mongo instance for the entire JVM.

    public Class MongoClient:

    A MongoDB client with internal connection pooling. For most applications, you should have one MongoClient instance for the entire JVM.

    Note: This class supersedes the Mongo class. While it extends  Mongo , it differs from it in that the default write concern is to wait for acknowledgment from the server of all write operations. In addition, its constructors accept instances of  MongoClientOptions and  MongoClientURI , which both also set the same default write concern.

    In general, users of this class will pick up all of the default options specified in MongoClientOptions . In particular, note that the default value of the connectionsPerHost option has been increased to 100 from the old default value of 10 used by the superceded  Mongo class.

    Mongo 是一个过期的类,取而代之的是MongoClient, 值得一提的是MongoClient把connection的默认值从以前的10个变成了现在的100个,省去了自定义配置的繁琐,很贴心。

    下面是我写的一个MongoConnectionFactory:

    public class MongoConnFactory {
    	private static MongoClient mongoClient = null;
    	@SuppressWarnings("deprecation")
    	public static  DB getDB() throws UnknownHostException {
    		
    		 DB conn = null;
    		 if(mongoClient == null){
    		     intializeMongoClient();
    				
    		}
    		String dbName = AppConfig.getValue(Const.MONGODB_DBNAME);
    		String username = AppConfig.getValue(Const.MONGODB_USERNAME);
    		String password = AppConfig.getValue(Const.MONGODB_PASSWORD);
    		conn = mongoClient.getDB(dbName);
    		conn.authenticate(username, password.toCharArray());
    		return conn;
    			
    		
    	}
    	private static void intializeMongoClient() throws UnknownHostException {
    		
    	    	String host = AppConfig.getValue(Const.MONGODB_HOST);
    		int port = AppConfig.getValueAsInteger(Const.MONGODB_PORT);
    		mongoClient = new MongoClient( host , port );
    		
    	}
    	public  static synchronized void closeConnection(){
    		
        		if(mongoClient != null){
        			
        		    mongoClient.close();
        			
        		}
    	}
    		
    	}

  • Lv 1

    主要的调整在于2.10.0版本中引入了MongoClient类,同时在其API中也说明了Mongo类会在将来的版本中被MongoClient替换(Note: This class has been superseded by MongoClient, and may be deprecated in a future release.)。故在这次调整中,也对原先的

    本帖下載内容已隐藏,请登入以查看隐藏内容!
    集群的应用只需要一个实例,所以这次调整我们设计成单例形式。如果出于某些原因,你决定使用多个实例,请注意:所有资源使用限制(最大连接数等等)对每个MongoClient都适用;销毁一个实例时,请确认调用MongoClient.close()方法来清理资源。

    下面给出相关的代码:

        /** 
          * 项目名: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);  
        } 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    
    /**
      * 项目名: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
        }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    

登录后回复
 

与 萌阔论坛 的连接断开,我们正在尝试重连,请耐心等待