天天看點

MongoDB與Java(1) - 建立連接配接

網上關于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();
           

一個構造函數不帶任何參數的版本。使用這個構造函數連接配接到的是本地的MongoDB服務,即/127.0.0.1:27017,當然你如果改變了MongoDB服務的端口,那麼這裡顯示的端口就是你的端口了。

我們可以通過以下單元測試代碼進行驗證:

@Test
public void testConstruactors() throws UnknownHostException {
	MongoClient client;
		
	client = new MongoClient();
	assertEquals(new ServerAddress(), client.getAddress());
	client.close();
}
           

 目前不需要關心ServerAddress類型,它主要作用于MongoDB服務相關的資訊。注意,跟其他DB Java Driver一樣,記得關閉連接配接。 當然,我們也可以指定連接配接的Host,看下面的單元測試:

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模式的方式建立并設定這些屬性的值。

MongoClientOptions customClientOptions = 
new MongoClientOptions.Builder().connectionsPerHost(50).build();
           

 分析下上面的代碼,MongoClientOptions.Builder()得到的是一個MongoClientOptions的Builder,通過該Builder可以設定各種Options,例如connectionsPerHost(50),設定連接配接池中連接配接個數,需要注意的是,每個屬性的設定方法的傳回類型是一個Builder,這意味着我們可以采用類似下面的鍊式調用:

MongoClientOptions customClientOptions = 
new MongoClientOptions.Builder().connectionsPerHost(50).maxWaitTime(2000).build()
           

 最後,當我們将需要的各項值設定好後,就調用Builder的builder()方法,得到一個MongoClientOptions對象。 問題來了,上面的代碼隻是為各項連接配接相關的屬性指派,那如何将這些值交給MongoClient,讓它按照我們給出的屬性值來建立連接配接呢? 答案就是MongoClient的構造函數,看下面的代碼:

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,如下:

MongoOptions mps = mongoClient.getMongoOptions();
mps.setConnectionsPerHost(mongoDBConfig.getPoolSize());
mps.setConnectTimeout(mongoDBConfig.getConnectTimeout());
mps.setMaxWaitTime(mongoDBConfig.getMaxWaitTime());
           

 不過我推薦MongoClientOptions,代碼更加優雅。另外,即使我們沒有設定MongoClientOptions,MongoClient也會有預設的設定,大家可以自己把他們列印出來看看。   1.3 使用連接配接字元串進行連接配接 上面的連接配接隻是指定了連接配接到MongoDB的服務,但是具體連接配接到哪個資料庫呢?使用什麼樣的登入名和密碼呢?這個時候就用到連接配接字元串了,我們先解釋下MongoDB的連接配接字元串,如下:

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,會以叢集的方式使用,  叢集中一台主服務,多個從服務,這個時候,我們就要在連接配接字元串中列出來,例如:

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:[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版本中才開始提供,請大家注意。

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個連接配接

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上設定讀寫政策:

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

注意注釋處的代碼。

連接配接操作就講到這裡,我們并沒有将連接配接的所有API都講到,隻是希望在這裡起個抛磚引玉的作用。謝謝大家!