您的位置:首页 > 数据库 > Mongodb

MongoDB 连接 for java

2015-03-30 10:47 183 查看
网上关于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:pwd@127.0.0.1/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:test123@127.0.0.1/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<MongoCredential> lstCredentials =   

        Arrays.asList(MongoCredential.createMongoCRCredential(  

            "admin", "myinfo", "123456".toCharArray()));  

client = new MongoClient(new ServerAddress("127.0.0.1"),lstCredentials, clientOptions);  

client.close();  

 首先注意List<MongoCredential> lstCredentials = 
 Arrays.asList(MongoCredential.createMongoCRCredential("admin", "myinfo", "123456".toCharArray()));这一句代码,使用了MongoCredential的静态方法createMongoCRCredential创建MongoCredential,createMongoCRCredential会创建使用通用安全服务应用程序接口来完全的访问MongoDB.另外,因为MongoClient要求一个List<MongoCredential> ,所以我们这里使用了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<ServerAddress> addresses = new ArrayList<ServerAddress>();  

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<ServerAddress> addresses = new ArrayList<ServerAddress>();  

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
plaincopyprint?





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
plaincopyprint?





/** 

     * 保存 

     *  

     * @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);  

    }  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息