网上关于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.在讨论连接字符串等内容之前,我们来看看它最简单的使用方式:
- MongoClient client = new MongoClient();
我们可以通过以下单元测试代码进行验证:
- @Test
- public void testConstruactors() throws UnknownHostException {
- MongoClient client;
- client = new MongoClient();
- assertEquals(new ServerAddress(), client.getAddress());
- client.close();
- }
- client = new MongoClient("127.0.0.1");
- assertEquals(new ServerAddress("127.0.0.1"), client.getAddress());
- client.close();
- MongoClientOptions customClientOptions =
- new MongoClientOptions.Builder().connectionsPerHost(50).build();
- MongoClientOptions customClientOptions =
- new MongoClientOptions.Builder().connectionsPerHost(50).maxWaitTime(2000).build()
- 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 mps = mongoClient.getMongoOptions();
- mps.setConnectionsPerHost(mongoDBConfig.getPoolSize());
- mps.setConnectTimeout(mongoDBConfig.getConnectTimeout());
- mps.setMaxWaitTime(mongoDBConfig.getMaxWaitTime());
- mongodb://user1:pwd@127.0.0.1/test?authMechanism=MONGODB-CR&maxPoolSize=500
大家可以看到,大部分内容是可选的,也就是说,最简单的连接字符串就是
mongodb://127.0.0.1
当然,真正在项目中,没人会这么用。
我们发现了一个有趣的地方,就是可以提供多个host和port.这是因为,我们使用MongoDB,会以集群的方式使用, 集群中一台主服务,多个从服务,这个时候,我们就要在连接字符串中列出来,例如:
- mongodb://host1,host2,host3/?connect=direct;slaveOk=true
MongoDB的连接字符串就简单介绍到这里,不了解的童鞋可以去http://www.w3cschool.cc/mongodb/mongodb-connections.html看看。
回到主题,在MongoClient中,如何使用连接字符串进行连接呢?MongoDB Java Driver提供了一个com.mongodb.MongoClientURI类型,使用方式如下:
- 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版本中才开始提供,请大家注意。
- 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();
- 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();
1.7 连接副本集
使用MongoDB作为数据库,基本上都会使用副本集,在这个集里面,有primary节点,又有其他secondary节点,并使用了读写分离,这个时候,使用java连接MongoDB服务应该怎么做呢? 其实很简单,就是使用一个ServerAddress集合保存副本集中的所有节点,然后作为MongoClient的构造函数的参数,并使用ReadPreference设置读写策略,注意,ReadPreference的读写策略既可以在MongoClient上设置,作用与使用MongoClient连接的所有操作,也可以设置到每次具体的集合操作上,作用域该次操作。代码如下:
在MongoClient上设置读写策略:
- 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());
- 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:这个控制是否在一个连接时,系统会自动重试