java連線MongoDB與MongoDB增刪改查詳解
1.MongoDB簡介
1.1什麼是MongoDB
MongoDB 是一個跨平臺的,面向文件的資料庫,是當前 NoSQL 資料庫產品中最熱門的一種。它介於關係資料庫和非關係資料庫之間,是非關係資料庫當中功能最豐富,最像關係資料庫的產品。它支援的資料結構非常鬆散,是類似JSON 的 BSON 格式,因此可以儲存比較複雜的資料型別。
MongoDB 的官方網站地址是:http://www.mongodb.org/
1.2 MongoDB特點
MongoDB 最大的特點是他支援的查詢語言非常強大,其語法有點類似於面向物件的查詢語言,幾乎可以實現類似關係資料庫單表查詢的絕大部分功能,而且還支援對資料建立索引。它是一個面向集合的,模式自由的文件型資料庫。
具體特點總結如下:
(1)面向集合儲存,易於儲存物件型別的資料
(2)模式自由
(3)支援動態查詢
(4)支援完全索引,包含內部物件
(5)支援複製和故障恢復
(6)使用高效的二進位制資料儲存,包括大型物件(如視訊等)
(7)自動處理碎片,以支援雲端計算層次的擴充套件性
(8)支援 Python,PHP,Ruby,Java,C,C#,Javascript,Perl 及 C++語言的驅動程式,社群中也提供了對 Erlang 及.NET 等平臺的驅動程式
(9) 檔案儲存格式為 BSON(一種 JSON 的擴充套件)
1.3 MongoDB體系結構
MongoDB 的邏輯結構是一種層次結構。主要由:
文件(document)、集合(collection)、資料庫(database)這三部分組成的。邏輯結構是面向使用者
的,使用者使用 MongoDB 開發應用程式使用的就是邏輯結構。
(1)MongoDB 的文件(document),相當於關係資料庫中的一行記錄。
(2)多個文件組成一個集合(collection),相當於關係資料庫的表。
(3)多個集合(collection),邏輯上組織在一起,就是資料庫(database)。
(4)一個 MongoDB 例項支援多個數據庫(database)。
文件(document)、集合(collection)、資料庫(database)的層次結構如下圖:
下表是MongoDB與MySQL資料庫邏輯結構概念的對比
MongoDb 關係型資料庫Mysql
資料庫(databases) 資料庫(databases)
集合(collections) 表(table)
文件(document) 行(row)
2.安裝與啟動
2.1安裝設定
雙擊“資源”中的“mongodb-win32-x86_64-2008plus-ssl-3.2.10-signed.msi”
按照提示步驟安裝即可。安裝完成後,軟體會安裝在C:\Program Files\MongoDB 目錄中。
我們要啟動的服務程式就是C:\Program Files\MongoDB\Server\3.2\bin目錄下的mongod.exe,為了方便我們每次啟動,我將C:\Program Files\MongoDB\Server\3.2\bin 設定到環境變數path中。
2.2啟動服務
(1)首先開啟命令提示符,建立一個用於存放資料的目錄
(2)啟動服務
dbpath引數用於指定資料儲存目錄
啟動後效果如下:
我們在啟動資訊中可以看到,mongoDB的預設埠是27017
如果我們不想按照預設埠啟動,可以通過–port 命令來修改埠
2.3登陸系統
我們另外開啟命令提示符視窗,如果mongoDB是按預設的埠啟動的,並且是部署在本機的。輸入命令 mongo 即可登陸系統
從介面輸出的資訊我們可以得知,它預設連線的是test資料庫
如果是要連線遠端的mongoDB伺服器 ,就輸入命令
mongo 遠端IP地址
如果遠端的mongoDB服務埠不是預設的,需要輸入命令
mongo 遠端IP地址:埠
輸入exit命令可退回到命令提示符
3.基本增刪改查操作
3.1選擇或建立資料庫
使用use 資料庫名稱即可選擇資料庫,如果該資料庫不存在會自動建立
3.2插入文件
文件相當於關係資料庫中的記錄
首先我們定義一個文件變數,格式為變數名稱={}; 例如:
接下來就是將這個變數存入MongoDB
格式為:
db.集合名稱.save(變數);
這裡的集合就相當於關係資料庫中的表。例如:
這樣就在student集合中存入文件。如果這個student集合不存在,就會自動建立。
當然,你也可以不用定義變數,直接把變數值放入save方法中也是可以地。
為了方便後期測試,我們再多加點資料
db.student.save({name:”沙和尚”,sex:”男”,age:25,address:”流沙河路11號”});
db.student.save({name:”唐僧”,sex:”男”,age:35,address:”東土大唐”});
db.student.save({name:”白骨精”,sex:”女”,age:18,address:”白骨洞”});
db.student.save({name:”白龍馬”,sex:”男”,age:20,address:”西海”});
db.student.save({name:”哪吒”,sex:”男”,age:15,address:”蓮花灣小區”});
3.3查詢集合
我們要查詢某集合的所有文件,使用find()方法。語法格式為:
db.集合名稱.find();
例如,我們要查詢student集合中的所有文件:
這裡你會發現每條文件會有一個叫_id的欄位,這個相當於我們原來關係資料庫中表的主鍵,當你在插入文件記錄時沒有指定該欄位,MongDB會自動建立,其型別是ObjectID型別。
如果我們在插入文件記錄時指定該欄位也可以,其型別可以使ObjectID型別,也可以是MongoDB支援的任意型別. 例如:
我們再次查詢
如果我想按一定條件來查詢,比如我想查詢性別為“女”的記錄,怎麼辦?很簡單!
只要在find()中新增引數即可,引數也是json格式,如下:
為了避免遊標可能帶來的開銷,MongoDB還提供了一個叫findOne()的方法,用來返回結果集的第一條記錄。
性別為男的有很多條,這裡只返回了第一條記錄。
當我們需要返回查詢結果的前幾條記錄時,可以使用limit方法,例如:
3.4修改文件
我們要想修改記錄,可以使用update方法 .
例如:我向將姓名為孫悟空的學員文件中的age欄位值改為31,執行下列語句,看會發生什麼?
再次查詢:
哦,悲劇了~~ 原來的孫悟空的文件只剩下_id 和age兩個欄位了。
那如何保留其它欄位值呢?
我們需要使用MongoDB提供的修改器$set 來實現,請看下列程式碼。
再次查詢,會發現“豬八戒”文件中原有的其它欄位還保留下來,而更新age欄位也成功了。
3.5刪除文件
刪除文件使用remove()方法,格式為:
db.集合名稱.remove( 條件 );
請慎用remove({}), 它會一條不剩地把你的集合所有文件刪的乾乾淨淨。
我們現在演示一下,刪除name為“哪吒”的記錄:
再次查詢,會發現哪吒的文件不見了。
4.高階查詢
4.1模糊查詢
MongoDB的模糊查詢是通過正則表示式的方式實現的。格式為:
/模糊查詢字串/
例如,我要查詢student集合中address欄位中含有“洞”的所有文件,程式碼如下:
如果要查詢name欄位中以“白”開頭的,程式碼如下:
4.2 Null值處理
如果我們想找出集合中某欄位值為空的文件,如何查詢呢?其實和我們之前的條件查詢是一樣的,條件值寫為null就可以了。
我們現在集合中的文件都是沒有空值的,為了方便測試,現在我們將資料做些修改:
將“唐僧”的address改為空
再次查詢:
我們會發現不僅會顯示“唐僧”這條文件,之前因為修改導致address欄位丟失的那條記錄也出現了。也就是說,這種查詢會查詢出該欄位為null的以及不存在該欄位的文件記錄。
4.3大於小於
<, <=, >, >= 這個操作符也是很常用的,格式如下
db.collection.find({ “field” : { gt: value } } ); // 大於: field > value
db.collection.find({ “field” : {lt: value } } ); // 小於: field < value
db.collection.find({ “field” : { gte: value } } ); // 大於等於: field >= value
db.collection.find({ “field” : {lte: value } } ); // 小於等於: field <= value
示例:查詢年齡大於等於20歲的學員記錄
4.4不等於
不等於使用$ne操作符。
示例:查詢sex欄位不為“男”的文件
4.5判斷欄位是否存在
判斷欄位是否存在使用$exists操作符。
示例:查詢所有含有address字元的文件。
示例:查詢所有不含有address字元的文件。
4.6包含與不包含
包含使用$in操作符。
示例:查詢student集合中age欄位包含20,25,30的文件
示例:查詢student集合中age欄位不包含20,25,30的文件
4.7統計記錄條數
統計記錄條件使用count()方法。
示例:查詢student集合的文件條數。
示例:查詢student集合中age欄位小於等於20的文件條數。
4.8 條件連線–並且
我們如果需要查詢同時滿足兩個以上條件,需要使用
示例:查詢student集合中age大於等於20 並且age小於30的文件
4.9 條件連線–或者
如果兩個以上條件之間是或者的關係,我們使用
格式為:$or:[ { },{ },{ } ]
示例:查詢student集合中sex為女,或者年齡小於20的文件記錄
5.java連線MongoDB
5.1查詢文件
5.1.1查詢全部記錄
(1)建立maven工程mongoDBDemo ,引入依賴。
<dependencies>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
(2)編寫程式碼,遍歷student集合所有資料:
MongoClient client=new MongoClient();//建立連線物件
MongoDatabase database = client.getDatabase("itcastdb");//獲取資料庫
MongoCollection<Document> collection = database.getCollection("student");//獲取集合
FindIterable<Document> list = collection.find();//獲取文件集合
for( Document doc: list){//遍歷集合中的文件輸出資料
System.out.println("name:"+ doc.getString("name") );
System.out.println("sex:"+ doc.getString("sex") );
System.out.println("age:"+ doc.getDouble("age") );//預設為浮點型
System.out.println("address:"+ doc.getString("address") );
System.out.println("--------------------------");
}
MongoDB的數字型別預設使用64位浮點型數值。{“x”:3.14}或{“x”:3}。對於整型值,可以使用NumberInt(4位元組符號整數),{“x”:NumberInt(“3”)} 或NumberLong(8位元組符號整數){“x”:NumberLong(“3”)}
5.1.2匹配查詢
MongoDB使用BasicDBObject型別封裝查詢條件,構造方法的引數為key 和value .
示例:查詢student集合中name為豬八戒的文件
//構建查詢條件
BasicDBObject bson=new BasicDBObject("name", "豬八戒");
FindIterable<Document> list = collection.find(bson);//獲取文件集合
//....遍歷集合
5.1.3模糊查詢
構建模糊查詢條件是通過正則表示式的方式來實現的
(1)完全匹配Pattern pattern = Pattern.compile(“^name
(3)左匹配Pattern pattern = Pattern.compile(“^name.*$”);
(4)模糊匹配Pattern pattern = Pattern.compile(“^.name.$”);
示例:模糊查詢student集合中address 中含有洞的文件記錄
//模糊查詢:like %洞%
Pattern queryPattern = Pattern.compile("^.*洞.*$");
BasicDBObject bson=new BasicDBObject("address", queryPattern);
FindIterable<Document> list = collection.find(bson);//獲取文件集合
//....遍歷集合
5.1.4大於小於
在MongoDB提示符下條件json字串為{ age: { $lt :20 } } ,對應的java程式碼也是BasicDBObject 的巢狀。
示例:查詢student集合中age小於20的文件記錄
//查詢年齡小於20的
BasicDBObject bson=new BasicDBObject("age", new BasicDBObject("$lt",20));
FindIterable<Document> list = collection.find(bson);//獲取文件集
//....遍歷集合
5.1.5條件連線–並且
示例:查詢年齡大於等於20並且小於30的文件記錄
//查詢年齡大於等於20的
BasicDBObject bson1=new BasicDBObject("age", new BasicDBObject("$gte",20));
//查詢年齡小於30的
BasicDBObject bson2=new BasicDBObject("age", new BasicDBObject("$lt",30));
//構建查詢條件and
BasicDBObject bson=new BasicDBObject("$and", Arrays.asList(bson1,bson2) );
5.1.6條件連線–或者
示例:查詢年齡小於等於20或者性別為女的文件記錄
BasicDBObject bson1=new BasicDBObject("age", new BasicDBObject("$lte",20));
BasicDBObject bson2=new BasicDBObject("sex", "女");
//構建查詢條件or
BasicDBObject bson=new BasicDBObject("$or", Arrays.asList( bson1, bson2 ) );
5.2增加文件
我們使用insertOne方法來插入文件。
示例:新增文件記錄–名稱:鐵扇公主 性別:女 年齡:28 地址:芭蕉洞
//獲取連線
MongoClient client=new MongoClient();
//得到資料庫
MongoDatabase database = client.getDatabase("itcastdb");
//得到集合封裝物件
MongoCollection<Document> collection = database.getCollection("student");
Map<String, Object> map=new HashMap();
map.put("name", "鐵扇公主");
map.put("sex", "女");
map.put("age", 35.0);
map.put("address", "芭蕉洞");
Document doc=new Document(map);
collection.insertOne(doc);//插入一條記錄
//collection.insertMany(documents);//一次性插入多條文件
5.3刪除文件
示例:將名稱為鐵扇公主的文件刪除
//獲取連線
MongoClient client=new MongoClient();
//得到資料庫
MongoDatabase database = client.getDatabase("itcastdb");
//得到集合封裝物件
MongoCollection<Document> collection = database.getCollection("student");
BasicDBObject bson=new BasicDBObject("name", "鐵扇公主");
collection.deleteOne(bson);//刪除記錄(符合條件的第一條記錄)
//collection.deleteMany(bson);//刪除符合條件的全部記錄
5.4修改文件
示例:將紅孩兒的地址修改為“南海”
//獲取連線
MongoClient client=new MongoClient();
//得到資料庫
MongoDatabase database = client.getDatabase("itcastdb");
//得到集合封裝物件
MongoCollection<Document> collection = database.getCollection("student");
//修改的條件
BasicDBObject bson= new BasicDBObject("name", "紅孩兒");
//修改後的值
BasicDBObject bson2 = new BasicDBObject("$set",new BasicDBObject("address", "南海"));
//引數1:修改條件 引數2:修改後的值
collection.updateOne(bson, bson2);
//collection.updateMany(filter, update);//修改符合條件的所有記錄
updateMany方法用於修改符合條件的所有記錄
updateOne方法用於修改符合條件的第一條記錄
6.MongoDB連線池
6.1程式碼實現
MongoClient 被設計為執行緒安全的類,也就是我們在使用該類時不需要考慮併發的情況,這樣我們可以考慮把MongoClient 做成一個靜態變數,為所有執行緒公用,不必每次都銷燬。這樣可以極大提高執行效率。實際上,這是MongoDB提供的內建的連線池來實現的。
首先我們先建立一個“管理類”,相當於我們原來的BaseDao
package cn.itcast.demo;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientOptions.Builder;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoDatabase;
public class MongoManager {
private static MongoClient mongoClient=null;
//對mongoClient初始化
private static void init(){
mongoClient=new MongoClient();
}
public static MongoDatabase getDatabase(){
if(mongoClient==null){
init();
}
return mongoClient.getDatabase("itcastdb");
}
}
然後我們建立一個StudentDao
package cn.itcast.demo;
import org.bson.Document;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
/**
* 學員資料訪問層
* @author Administrator
*
*/
public class StudentDao {
public void save(String name,String sex,double age,String address){
MongoDatabase database = MongoManager.getDatabase();
MongoCollection<Document> collection = database.getCollection("student2");
Document docment=new Document();
docment.put("name", name);
docment.put("sex", sex);
docment.put("age", age);
docment.put("address", address);
collection.insertOne(docment);
}
}
我們現在做個測試,迴圈插入2萬條資料,看看執行時間是多長時間
package cn.itcast.demo;
import java.util.Date;
public class TestPool {
public static void main(String[] args) {
long startTime = new Date().getTime();//開始時間
StudentDao studentDao=new StudentDao();
for(int i=0;i<20000;i++){
studentDao.save("測試"+i, "男", 25.0, "測試地址"+i);
}
long endTime = new Date().getTime();//完成時間
System.out.println("完成時間:"+(endTime-startTime)+"毫秒");
}
}
經過測試:所用毫秒數為3589
6.2引數設定
我們在剛才的程式碼基礎上進行連線池引數的設定
修改MongoManager的init方法
//對mongoClient初始化
private static void init(){
//連線池選項
Builder builder = new MongoClientOptions.Builder();//選項構建者
builder.connectTimeout(5000);//設定連線超時時間
builder.socketTimeout(5000);//讀取資料的超時時間
builder.connectionsPerHost(30);//每個地址最大請求數
builder.writeConcern(WriteConcern.NORMAL);//寫入策略,僅丟擲網路異常
MongoClientOptions options = builder.build();
mongoClient=new MongoClient("127.0.0.1",options);
}
再次進行測試:所用的毫秒1544
下面是寫入策略。
WriteConcern.NONE:沒有異常丟擲
WriteConcern.NORMAL:僅丟擲網路錯誤異常,沒有伺服器錯誤異常
WriteConcern.SAFE:丟擲網路錯誤異常、伺服器錯誤異常;並等待伺服器完成寫操作。
WriteConcern.MAJORITY: 丟擲網路錯誤異常、伺服器錯誤異常;並等待一個主伺服器完成寫操作。
WriteConcern.FSYNC_SAFE: 丟擲網路錯誤異常、伺服器錯誤異常;寫操作等待伺服器將資料重新整理到磁碟。
WriteConcern.JOURNAL_SAFE:丟擲網路錯誤異常、伺服器錯誤異常;寫操作等待伺服器提交到磁碟的日誌檔案。
WriteConcern.REPLICAS_SAFE:丟擲網路錯誤異常、伺服器錯誤異常;等待至少2臺伺服器完成寫操作。
7.綜合案例-《網站點選日誌分析元件》
7.1需求分析
《花生二手車》交易網站日訪問IP高達2萬+ ,每秒點選頻率在2000次左右。為了能夠對訪問使用者的行為做進一步的分析,產品部提出需求,使用者每次點選瀏覽二手車都要記錄該使用者ID、訪問IP、訪問時間、點選車型、點選商品ID、價格等資訊。
7.2資料庫設計
瀏覽日誌browseLog
欄位名稱 欄位型別 欄位含義
userid 字元 使用者ID
ip 字元 訪問IP
browseTime 時間 訪問時間
model 字元 點選車型
goodsid 字元 點選商品ID
price 數值 價格
remark 字元 備註
7.3日誌寫入
(1)建立工程sitelog ,在pom.xml中引入依賴。
<dependencies>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
(2)在src/main/resources 新增配置檔案sitelog.properties
host=127.0.0.1
port=27017
這個配置檔案用於配置主機地址和埠
(3)建立包com.huasheng.sitelog,建立Config 類,用於讀取配置檔案
package com.huasheng.sitelog;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 配置類
* @author Administrator
*
*/
public class Config {
static{
try {
Properties p=new Properties();
InputStream input=Config.class.getResourceAsStream("/sitelog.propertis");
p.load(input);
host=p.getProperty("host");
port=Integer.parseInt( p.getProperty("port"));
input.close();
} catch (IOException e) {
e.printStackTrace();
}//載入
}
private static String host;//主機地址
private static int port;//埠
public static String getHost() {
return host;
}
public static int getPort() {
return port;
}
}
(4)建立管理類
package com.huasheng.sitelog;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientOptions.Builder;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoDatabase;
/**
* Mongo資料庫連線管理類
* @author Administrator
*
*/
public class MongoManager {
private static MongoClient mongoClient=null;
//初始化
private static void init(){
//建立一個選項構造器
Builder builder = new MongoClientOptions.Builder();
builder.connectTimeout(5000);//設定連線超時時間
builder.socketTimeout(5000);//讀取資料的超時時間
builder.connectionsPerHost(30);//設定每個地址最大連線數
builder.writeConcern(WriteConcern.NORMAL);//設定寫入策略 ,只有網路異常才會丟擲
//得到選項封裝
MongoClientOptions options = builder.build();
mongoClient=new MongoClient(new ServerAddress(Config.getHost(), Config.getPort()),options);
}
public static MongoDatabase getDatabase(){
if(mongoClient==null){
init();
}
return mongoClient.getDatabase("itcastdb");
}
}
(5)日誌工具類
package com.huasheng.sitelog;
import java.util.Map;
import org.bson.Document;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
/**
* 站點日誌資料工具類
* @author Administrator
*
*/
public class SiteLogUtil {
/**
* 寫入日誌
* @param logname 日誌名稱
* @param map 日誌資料
*/
public static void save(String logname,Map<String, Object> map){
MongoDatabase database = MongoManager.getDatabase();
MongoCollection<Document> collection = database.getCollection(logname);
Document doc=new Document(map);
collection.insertOne(doc);
}
}
(6)編寫測試程式碼
Map map=new HashMap();
map.put("userid", "8888");
map.put("ip", "188.188.200.2");
map.put("browseTime", new Date());
map.put("model", "大眾");
map.put("goodsid", "123123");
map.put("price", 15.3);
map.put("remark", "八成新,賤賣了");
SiteLogUtil.save("browseLog", map);//存入日誌
7.4日誌查詢
7.4.1條件查詢
(1)在SiteLogUtil類中新增方法
/**
* 按條件查詢
* @param logName
* @param map
* @return
*/
public static FindIterable<Document> list(String logName,Map<String, Object> map){
MongoDatabase database = MongoManager.getDatabase();
MongoCollection<Document> collection = database.getCollection(logName);
BasicDBObject bson=new BasicDBObject(map);//構建查詢條件
return collection.find(bson);
}`
(2)編寫測試程式碼
Map<String, Object> map =new HashMap();
map.put("userid", "8888");
FindIterable<Document> list = SiteLogUtil.list("browseLog", map);
String json = JSON.serialize(list);
System.out.println(json);
7.4.2分頁查詢
(1)在SiteLogUtil類中新增方法
/**
* 分頁查詢日誌
* @param logName 日誌名稱
* @param map 條件
* @param pageIndex 頁碼
* @param pageSize 頁大小
* @return
*/
public static Map<String,Object> listPage(String logName,Map<String, Object> map,int pageIndex,int pageSize){
MongoDatabase database = MongoManager.getDatabase();
MongoCollection<Document> collection = database.getCollection(logName);
BasicDBObject bson=new BasicDBObject(map);//構建查詢條件
FindIterable<Document> find = collection.find(bson);
int skip= (pageIndex-1)*pageSize;
find.skip( skip);//跳過記錄數
find.limit(pageSize);//一頁查詢記錄數
//{ total:x,rows:[] }
long count = collection.count(bson);
Map<String,Object> m=new HashMap();
m.put("total", count);
m.put("rows", find);
return m;
}
(2)新增測試資料
for(int i=0;i<1000;i++){
Map<String, Object> map=new HashMap();
map.put("userid", "900"+i);//使用者ID
map.put("ip", "121.211.112.212");
map.put("browseTime", new Date());//瀏覽時間
map.put("model", "大眾"+i);//型號
map.put("goodsid", "123456");//商品ID
map.put("price", 11.8);//價格
map.put("remark", "八成新,快來買吧");
SiteLogUtil.save("browseLog", map);
}
(3)編寫測試程式碼:
Map<String, Object> map=new HashMap();
map.put("goodsid", "123456");
Map<String, Object> m = SiteLogUtil.listPage("browseLog", map, 2, 10);
String json = JSON.serialize(m);
System.out.println(json);
使用Maven 的package命令進行打包。
建立WEB工程,引入jar包,呼叫此方法即可實現日誌查詢。程式碼略。