Spring MVC中使用Mongodb總結
阿新 • • 發佈:2018-12-24
近期專案做了次架構調整,原來是使用MySQL+GeoHash來儲存LBS資料(地理位置資訊),現在使用NOSQL資料庫Mongodb來儲存LBS資料(地理位置資訊)。由於專案是基於Spring MVC開發的,今天就Mongodb的使用做下總結。
Spring MVC 整合Mongodb
1.載入jar,maven配置
<!-- 新加入的spring整合mongodb的包 開始 -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId >mongo-java-driver</artifactId>
<version>2.13.0-rc0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version >1.7.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-cross-store</artifactId>
<version>1.7.1.RELEASE</version>
</dependency >
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-log4j</artifactId>
<version>1.7.1.RELEASE</version>
</dependency>
<!-- 新加入的spring整合mongodb的包 結束 -->
2.配置
Mongodb分2種方法整合,分別是單機和叢集方式。
單機配置
applicationContext.xml
<mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" >
<mongo:options connections-per-host="${mongo.connectionsPerHost}"
threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
connect-timeout="${mongo.connectTimeout}" max-wait-time="${mongo.maxWaitTime}"
auto-connect-retry="${mongo.autoConnectRetry}" socket-keep-alive="${mongo.socketKeepAlive}"
socket-timeout="${mongo.socketTimeout}" slave-ok="${mongo.slaveOk}" write-number="1"
write-timeout="0" write-fsync="true"/>
</mongo:mongo>
配置檔案common-config.properties
mongo.dbname = test_db #資料庫名稱
mongo.password = test_pwd #密碼
mongo.username = test_user #使用者名稱
mongo.host = 127.0.0.1 #主機
mongo.port= 27017 #埠號
mongo.connectionsPerHost= 8 #一個執行緒變為可用的最大阻塞數
mongo.threadsAllowedToBlockForConnectionMultiplier= 4 #執行緒佇列數,它以上面connectionsPerHost值相乘的結果就是執行緒佇列最大值
mongo.connectTimeout= 1500 #連線超時時間(毫秒)
mongo.maxWaitTime= 1500 #最大等待時間
mongo.autoConnectRetry= true #自動重連
mongo.socketKeepAlive= true #scoket保持活動
mongo.socketTimeout=1500 #scoket超時時間
mongo.slaveOk=true #讀寫分離
叢集配置
applicationContext.xml
<mongo:mongo id="mongo" replica-set="${mongo.replicaSet}">
<mongo:options connections-per-host="${mongo.connectionsPerHost}"
threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
connect-timeout="${mongo.connectTimeout}" max-wait-time="${mongo.maxWaitTime}" auto-connect-retry="${mongo.autoConnectRetry}"
socket-keep-alive="${mongo.socketKeepAlive}" socket-timeout="${mongo.socketTimeout}" slave-ok="${mongo.slaveOk}"
write-number="${mongo.writeNumber}" write-fsync="${mongodb.writeFsync}" />
</mongo:mongo>
配置檔案common-config.properties
mongo.dbname = test_db
mongo.username = test_user
mongo.password = test_pwd
mongo.replicaSet = 192.168.2.193:27017,192.168.2.192:27017
mongo.connectionsPerHost= 100
mongo.threadsAllowedToBlockForConnectionMultiplier=50
mongo.connectTimeout=3000
mongo.maxWaitTime=5000
mongo.autoConnectRetry=true
mongo.socketKeepAlive=true
mongo.socketTimeout=5000
mongo.slaveOk=true
mongo.writeNumber = 1
mongodb.writeFsync = true
其他配置
<!-- 使用者驗證 -->
<bean id="userCredentials" class="org.springframework.data.authentication.UserCredentials">
<constructor-arg name="username" value="${mongo.username}" />
<constructor-arg name="password" value="${mongo.password}" />
</bean>
<!-- mongo的工廠,通過它來取得mongo例項,dbname為mongodb的資料庫名,沒有的話會自動建立 -->
<bean id="mongoDbFactory"
class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
<constructor-arg ref="mongo" />
<constructor-arg value="${mongo.dbname}" />
<constructor-arg ref="userCredentials" />
</bean>
<bean id="mappingContext"
class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />
<bean id="defaultMongoTypeMapper"
class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper">
<constructor-arg name="typeKey">
<null />
</constructor-arg>
</bean>
<!-- collection的對映 -->
<bean id="mappingMongoConverter"
class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mappingContext" />
<property name="typeMapper" ref="defaultMongoTypeMapper" />
</bean>
<!-- mongodb的主要操作物件,所有對mongodb的增刪改查的操作都是通過它完成 -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mongoConverter" ref="mappingMongoConverter" />
</bean>
Mongodb增刪改查
1.Mongodb物件模型
Dynamic.java
@Document(collection = "Dynamic")
public class Dynamic implements Serializable{
/**
*
*/
private static final long serialVersionUID = 179822189115264434L;
private String _id;
private String userId; //使用者ID
private Date releaseDate;//釋出日期
private double []loc = new double[2];//位置
public void setId(String _id) {
this._id = _id;
}
public String getId() {
return this._id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Date getReleaseDate() {
return releaseDate;
}
public void setReleaseDate(Date releaseDate) {
this.releaseDate = releaseDate;
}
public double[] getLoc() {
return loc;
}
public void setLoc(double[] loc) {
this.loc = loc;
}
}
2.程式碼示例
新增
Dynamic dynamic = New Dynamic();
dynamic.setUserId("10023");
// ...
// set屬性,自己補全
// 轉換為DBObject
DBObject dbObject = BeanUtil.bean2DBObject(dynamic);
db.removeField("serialVersionUID");
// 儲存
mongoTemplate.getCollection(collection).save(dbObject)
更新
普通更新
DBObject aim = new BasicDBObject("_id", id);
DBObject setValue = new BasicDBObject();
setValue.put("loc", loc.getLoc());
// 更新的值,用$set
DBObject updateSetValue = new BasicDBObject("$set", setValue);
//更新,aim:where條件 updateSetValue:更新值 true:是否沒有記錄時插入 false:是否多行更新
mongoTemplate.getCollection(collection).update(aim, updateSetValue , true,
false);
陣列更新
DBObject addAim = new BasicDBObject();
addAim.put("_id", id);
//資料中push值
DBObject updateSetValue = new BasicDBObject("$push", addedValue);
//增加
updateSetValue.put("$inc", new BasicDBObject("commentSize", 1));
mongoTemplate.getCollection(collection).update(addAim, updateSetValue);
查詢
單條查詢
DBObject query = new BasicDBObject("_id", id);
DBObject fields = new BasicDBObject();
mongoTemplate.getCollection(collection).findOne(query, fields)
分頁查詢
int pageSize = 20;
int pageNum = 1;
DBObject fields = new BasicDBObject();
//排序,-1 降序
DBObject orderBy = new BasicDBObject("release_date", -1);
//分頁查詢
List<DBObject> list = new ArrayList<>();
Cursor cursor = mongoTemplate.getCollection(collection)
.find(query, fields).skip((pageNum - 1) * pageSize)
.limit(pageSize).sort(orderBy);
while (cursor.hasNext()) {
list.add(cursor.next());
}
範圍查詢
DBObject query = new BasicDBObject();
// $lte 小於等於,$lt 小於
query.put(
"release_date",
new BasicDBObject("$lte", DateUtil.parseDate(
maxTime, DateStyle.YYYY_MM_DD_HH_MM_SS_SSS
.getValue())));
// $gte 大於等於,$gt 大於
query.put(
"release_date",
new BasicDBObject("$gte", DateUtil.parseDate(
minTime, DateStyle.YYYY_MM_DD_HH_MM_SS_SSS
.getValue())));
in 和not in 查詢
// $in 查詢
DBObject query = new BasicDBObject("qd_id", new BasicDBObject(
"$in", idStr))
// $nin 查詢
DBObject query = new BasicDBObject("qd_id", new BasicDBObject(
"$nin", idStr))
or 查詢
List orArry = new ArrayList<>();
orArry.add(new BasicDBObject("qd_id", new BasicDBObject(
"$in", qd_ids.toArray())));
orArry.add(new BasicDBObject("_id", new BasicDBObject("$in", recommondIds.toArray())));
query.put("$or", orArry);
聚合查詢sum和group by
Map retMap = new HashMap<>();
// $group 分組,newsCount別名,$sum和,$commentSize欄位名
String groupStr = "{$group:{_id:null,newsCount:{$sum:1},commentCount:{$sum:\"$commentSize\"},supportCount:{$sum:\"$supportSize\"}}}";
DBObject group = (DBObject) JSON.parse(groupStr);
String minTime = (String)params.get("start") + " 00:00:00:000";
String maxTime = (String)params.get("end") + " 00:00:00:000";
BasicDBObject query = new BasicDBObject();
query.put(
"release_date",
new BasicDBObject("$gte", DateUtil.parseDate(
minTime, DateStyle.YYYY_MM_DD_HH_MM_SS_SSS
.getValue())));
query.put(
"release_date",
new BasicDBObject("$lte", DateUtil.parseDate(
maxTime, DateStyle.YYYY_MM_DD_HH_MM_SS_SSS
.getValue())).append("$gte",
DateUtil.parseDate(minTime,
DateStyle.YYYY_MM_DD_HH_MM_SS_SSS
.getValue())));
DBObject match = new BasicDBObject("$match", query);
// 聚合查詢
AggregationOutput output = mongoTemplate.getCollection(collection).aggregate(match,group);
for( Iterator< DBObject > it = output.results().iterator(); it.hasNext(); ){
BasicDBObject dbo = ( BasicDBObject ) it.next();
retMap = com.alibaba.fastjson.JSON.parseObject(dbo.toString(), Map.class);
}
return retMap;
LBS查詢(附近的人)
if (query == null)
query = new BasicDBObject();
List<DBObject> pipeLine = new ArrayList<>();
BasicDBObject pipeBasicDBObject = new BasicDBObject();
pipeBasicDBObject.append("near", new double[] { longitude, latitude })
.append("distanceField", "dist.calculated")
.append("spherical", true).append("query", query)
.append("distanceMultiplier", 6371);
if (qType == 1) {
double maxDistance = distance/6371.0000;
pipeBasicDBObject.append("maxDistance", maxDistance);
}
BasicDBObject aggregate = new BasicDBObject("$geoNear",
pipeBasicDBObject);
BasicDBObject orderObject = new BasicDBObject("$sort",
new BasicDBObject().append("dist.calculated", 1));
pipeLine.add(aggregate);
pipeLine.add(orderObject);
int startNo = (pageNum-1)*pageSize;
int limit = pageSize;
if(pageNum == 1)
{
limit = limit+1;
}
else
{
startNo = startNo+1;
}
if (qType == 1) {
BasicDBObject skipObject = new BasicDBObject("$skip", startNo);
pipeLine.add(skipObject);
}
BasicDBObject limitObject = new BasicDBObject("$limit", limit);
pipeLine.add(limitObject);
List<DBObject> list = new LinkedList<>();
try {
Cursor cursor = mongoTemplate.getCollection(collection).aggregate(
pipeLine, AggregationOptions.builder().build());
while (cursor.hasNext()) {
DBObject dBObject = cursor.next();
list.add(dBObject);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
刪除
DBObject deleAim = new BasicDBObject();
deleAim.put("_id", id);
mongoTemplate.getCollection(collection).remove(dbObject)
ps:上面示例不全,只附上了重要的程式碼。
至此,總共介紹了常用查詢,聚合查詢,刪除,儲存,geo查詢等方法。
個人技術分享微信公眾號,歡迎關注一起交流