成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

雙刃劍MongoDB的學(xué)習(xí)和避坑

everfight / 616人閱讀

摘要:雙刃劍的學(xué)習(xí)和避坑是一把雙刃劍,它對(duì)數(shù)據(jù)結(jié)構(gòu)的要求并不高。第二某些銀行顯示的金額不是實(shí)時(shí)的。第三步創(chuàng)建封裝類的管理類,針對(duì)不同的實(shí)體類,需要配置不同的。

雙刃劍MongoDB的學(xué)習(xí)和避坑

MongoDB 是一把雙刃劍,它對(duì)數(shù)據(jù)結(jié)構(gòu)的要求并不高。數(shù)據(jù)通過(guò)key-value的形式存儲(chǔ),而value的值可以是字符串,也可以是文檔。所以我們?cè)谑褂玫倪^(guò)程中非常方便。正是這種方便給我們埋下了一顆顆地雷。當(dāng)內(nèi)嵌的文檔太深,或者內(nèi)嵌文檔有相同的屬性名。你會(huì)被炸得很慘。本章節(jié)通過(guò) MongoDB簡(jiǎn)介,Shell編程,SpringBoot整合MongoDB,工作中注意事項(xiàng),四個(gè)方面介紹MongoDB的使用。讓你輕松入門,輕松避坑。還在等什么,趕快來(lái)學(xué)習(xí)吧!

技術(shù):MongoDB,SpringBoot,SpringDataMongoDB
說(shuō)明:本章重點(diǎn)介紹MongoDB的使用,對(duì)非關(guān)系型數(shù)據(jù)庫(kù)的介紹會(huì)比較簡(jiǎn)單。完整代碼和相關(guān)sql請(qǐng)移步github,ths!
源碼:https://github.com/ITDragonBl...

MongoDB 簡(jiǎn)介

MongoDB 是非關(guān)系型數(shù)據(jù)庫(kù)中,最接近關(guān)系型數(shù)據(jù)庫(kù)的,文檔型數(shù)據(jù)庫(kù)。它支持的查詢功能非常強(qiáng)大。
MongoDB 是為快速開(kāi)發(fā)互聯(lián)網(wǎng)Web應(yīng)用而設(shè)計(jì)的數(shù)據(jù)庫(kù)系統(tǒng)。他的數(shù)據(jù)模型是面向文檔的,這種文檔是一種類似于JSON的結(jié)構(gòu),準(zhǔn)確來(lái)說(shuō)是一種支持二進(jìn)制的BSON(Binary JSON)結(jié)構(gòu)。

非關(guān)系性數(shù)據(jù)庫(kù)

非關(guān)系性數(shù)據(jù)庫(kù) 也被稱為 NoSQL(Not only sql),主要有四大類:鍵值存儲(chǔ)數(shù)據(jù)庫(kù)、列存儲(chǔ)數(shù)據(jù)庫(kù)、文檔型數(shù)據(jù)庫(kù)、圖形數(shù)據(jù)庫(kù)。之前介紹的Redis屬于鍵值存儲(chǔ)數(shù)據(jù)庫(kù)。

關(guān)系與非關(guān)系型數(shù)據(jù)庫(kù)

關(guān)系型數(shù)據(jù)庫(kù)的優(yōu)點(diǎn):
1 支持事務(wù)處理,事務(wù)特性:原子性、一致性、隔離性、持久性。
2 數(shù)據(jù)結(jié)構(gòu)清晰,便于理解,可讀性高。
3 使用方便,有標(biāo)準(zhǔn)的sql語(yǔ)法。

關(guān)系型數(shù)據(jù)庫(kù)的缺點(diǎn):
1 讀寫性能相對(duì)較差,為保證事務(wù)的一致性,需要一定的開(kāi)銷。在高并發(fā)下表現(xiàn)的尤為突出。
2 表結(jié)構(gòu)固定,不易于表后期的擴(kuò)展,所以前期對(duì)表的設(shè)計(jì)要求較高。

非關(guān)系型數(shù)據(jù)庫(kù)的優(yōu)點(diǎn):
1 讀寫性能高,沒(méi)有保障數(shù)據(jù)的一致性。
2 表結(jié)構(gòu)靈活,表結(jié)構(gòu)并不是固定的,通過(guò)key-value存儲(chǔ)數(shù)據(jù),value又可以存儲(chǔ)其他格式的數(shù)據(jù)。

兩者的優(yōu)缺點(diǎn)其實(shí)是向反的,一件事物不會(huì)憑空出現(xiàn),都是在原有的基礎(chǔ)上做了補(bǔ)充和優(yōu)化,兩者的側(cè)重點(diǎn)各有不同。就像MySQL保障了數(shù)據(jù)的一致性,卻影響了讀寫的性能。MongoDB放棄數(shù)據(jù)的強(qiáng)一致性,保障了讀寫的效率。在合適的場(chǎng)景使用合適的數(shù)據(jù)庫(kù),是需要我們考慮的。
1 對(duì)于需要高度事務(wù)特性的系統(tǒng),比如和錢有關(guān)的,銀行系統(tǒng),金融系統(tǒng)。我們要考慮使用關(guān)系型數(shù)據(jù)庫(kù),確保數(shù)據(jù)的一致性和持久性。
2 對(duì)于那些數(shù)據(jù)并不是很重要,訪問(wèn)量又很大的系統(tǒng),比如電商平臺(tái)的商品信息。我們可以使用非關(guān)系型數(shù)據(jù)庫(kù)來(lái)做緩存,充分提高了系統(tǒng)查詢的性能。

這里對(duì)銀行和金融我想抱怨兩句:
第一:投資理財(cái)千萬(wàn)不要選擇小平臺(tái)金融公司,收益再高都是虛假的,多半都是圈錢跑路的,錢的教訓(xùn)。
第二:某些銀行APP顯示的金額不是實(shí)時(shí)的。16年某生銀行卡轉(zhuǎn)入40萬(wàn),但在我的總資產(chǎn)界面并沒(méi)有轉(zhuǎn)入的金額,嚇得我一身冷汗。顫抖著雙手給客服打了幾個(gè)電話才知道,某生銀行APP的總資產(chǎn)界面數(shù)據(jù)是統(tǒng)計(jì)前一天的。直到第二天,金額才顯示正確。從此我再也沒(méi)有用某生的銀行卡。某商的信用卡也是一樣,還了錢金額并沒(méi)有減下來(lái)。不知道現(xiàn)在有沒(méi)有改。

有在銀行工作的朋友,能否告訴我這樣設(shè)計(jì)的原因是啥?難道用戶體驗(yàn)不重要?還是要體現(xiàn)客服的價(jià)值?反正,這鍋我們程序員不背。

Mongodb Shell 編程 查詢數(shù)據(jù)

Mongodb的查詢功能十分強(qiáng)大,有find() 和 findOne()。支持的查詢條件有:$lt、$lte、$gt、$gte、$ne、$or、$in、$nin、$not、$exists、$and、正則表達(dá)式等。

db.collection.find() 根據(jù)查詢條件返回所有文檔

db.collection.findOne() 根據(jù)查詢條件返回第一個(gè)文檔

查詢建議:
1 查詢所有數(shù)據(jù),建議使用分頁(yè)查詢。
2 查詢key建議用引號(hào),對(duì)象的屬性可以省略引號(hào),內(nèi)嵌的對(duì)象屬性不能省略。比如下面的name可以省略,但address.province則不能。
3 盡量少用$or, $in 查詢,效率很低。

// 查詢所有(不推薦,一般使用分頁(yè)查詢)
db.itdragonuser.find();
{"_id":ObjectId("5a9bbefa2f3fdfdf540a1be7"),"name":"ITDragon","age":25,"address":{"province":"廣東省","city":"深圳"},"ability":["JAVA"]}
// 等于查詢
db.itdragonuser.find({"name":"ITDragon"});
// 模糊查詢
db.itdragonuser.find({"name":/ITDragon/});
// 或者查詢
db.itdragonuser.find({$or:[{"address.province":"湖北"},{"address.province":"湖南"}]});
// 包含查詢(包含了JAVA或者HTML)
db.itdragonuser.find({"ability":{$in:["JAVA","HTML"]}});
// 不包含查詢(JAVA和HTML都不包含)
db.itdragonuser.find({"ability":{$nin:["JAVA","HTML"]}});
// 范圍查詢$gt , $lt , $gte , $lte , $ne
db.itdragonuser.find({"age":{$gt:25}});
// 正則表達(dá)式查詢(查詢以WeiXin結(jié)尾的數(shù)據(jù))
db.itdragonuser.find({"name":/WeiXin$/});
// 按照條件統(tǒng)計(jì)數(shù)據(jù)
db.itdragonuser.count({"name":/ITDragon/});
// 過(guò)濾重復(fù)內(nèi)容(打印不重復(fù)的name值)
db.itdragonuser.distinct("name");
// sort:排序(1表示升序 -1表示降序),skip:跳過(guò)指定數(shù)量,limit:每頁(yè)查詢數(shù)量
db.itdragonuser.find().sort({"age":1}).skip(2).limit(3);
// 字段投影,(0表示不顯示,1表示顯示)
db.itdragonuser.find({},{_id:0,name:1,address:1,aliblity:1});
插入數(shù)據(jù)

插入數(shù)據(jù)比較簡(jiǎn)單,insert() 可以向集合插入一個(gè)或多個(gè)文檔,而insertOne() 和 insertMany() 細(xì)化了insert() 方法,語(yǔ)法是一樣的,命名規(guī)則上更清晰。

db.collection.insert() 可以向集合中插入一個(gè)或多個(gè)文檔

db.collection.insertOne() 向集合中插入一個(gè)文檔

db.collection.insertMany()向集合中插入多個(gè)文檔

插入建議:
1 插入數(shù)據(jù)不能破壞原有的數(shù)據(jù)結(jié)構(gòu),造成不必要的麻煩。
2 批量插入數(shù)據(jù),盡量一次執(zhí)行多個(gè)文檔,而不是多個(gè)文檔執(zhí)行多次方法。

// 插入一條數(shù)據(jù),類型有字符串,數(shù)字,對(duì)象,集合
db.itdragonuser.insert({"name":"ITDragon","age":24,"address":{"province":"廣東","city":"深圳"},"ability":["JAVA","HTML"]})
// 插入多條數(shù)據(jù)
db.itdragonuser.insert([
{"name":"ITDragon","age":24,"address":{"province":"廣東","city":"深圳"},"ability":["JAVA","HTML"]},
{"name":"ITDragonGit","age":24,"address":{"province":"湖北","city":"武漢"},"ability":["JAVA","HTML","GIT"]}
])
更新數(shù)據(jù)

更新數(shù)據(jù)時(shí),需要確保value的數(shù)據(jù)結(jié)構(gòu),是字符串,是集合,還是對(duì)象,不能破壞原有的數(shù)據(jù)結(jié)構(gòu)。盡量使用修改器來(lái)幫忙完成操作。

db.collection.update() 可以修改、替換集合中的一個(gè)或多個(gè)文檔,默認(rèn)修改第一個(gè),若要修改多個(gè),則需要使用multi:true

db.collection.updateOne() 修改集合中的一個(gè)文檔

db.collection.updateMany() 修改集合中的多個(gè)文檔

db.collection.replaceOne() 替換集合中的一個(gè)文檔

常用的修改器:
$inc : 數(shù)值類型屬性自增
$set : 用來(lái)修改文檔中的指定屬性
$unset : 用來(lái)刪除文檔的指定屬性
$push : 向數(shù)組屬性添加數(shù)據(jù)
$addToSet : 向數(shù)組添加不重復(fù)的數(shù)據(jù)

更新建議:
1 更新數(shù)據(jù)不能破壞原有的數(shù)據(jù)結(jié)構(gòu)。
2 正確使用修改器完成更新操作。

// 更新字符串屬性
db.itdragonuser.update({"name":"ITDragonGit"},{$set:{"name":"ITDragon"}});
// 更新對(duì)象屬性
db.itdragonuser.update({"name":"ITDragon"},{$set:{"address.province":"廣東省"}});
// 更新集合屬性
db.itdragonuser.update({"name":"ITDragon"},{$push:{"ability":"MONGODB"}});
// 批量更新屬性
db.itdragonuser.updateMany({"name":"ITDragon"},{$set:{"age":25}});
// 批量更新屬性,加參數(shù)multi:true
db.itdragonuser.update({"name":"ITDragon"},{$set:{"age":25}},{multi:true});
刪除數(shù)據(jù)

刪除數(shù)據(jù)是一個(gè)非常謹(jǐn)慎的操作,實(shí)際開(kāi)發(fā)中不會(huì)物理刪除數(shù)據(jù),只是邏輯刪除。方便數(shù)據(jù)恢復(fù)和大數(shù)據(jù)分析。這里只簡(jiǎn)單介紹。

db.collection.remove() 刪除集合中的一個(gè)或多個(gè)文檔(默認(rèn)刪除多個(gè))

db.collection.deleteOne() 刪除集合中的一個(gè)文檔

db.collection.deleteMany() 刪除集合中的多個(gè)文檔

SpringBoot MongoDB 整合

如果你覺(jué)得Spring整合MongoDB略顯麻煩,那SpringBoot整合MongoDB就是你的福音。SpringBoot旨在零配置,只需簡(jiǎn)單的兩個(gè)步驟即可。
第一步:在pom.xml文件中添加spring-boot-starter-data-mongodb

    
    org.springframework.boot
    spring-boot-starter-data-mongodb

第二步:在application.properties文件中配置MongoDB數(shù)據(jù)庫(kù)鏈接地址。
鏈接MongoDB數(shù)據(jù)庫(kù)地址規(guī)則:spring.data.mongodb.uri=mongodb://account:password@ip:port/database
其中 account和password方便是鏈接數(shù)據(jù)庫(kù)的賬號(hào)和密碼。而database是需要鏈接的數(shù)據(jù)庫(kù)地址

# 沒(méi)有賬號(hào)密碼可以簡(jiǎn)寫
spring.data.mongodb.uri=mongodb://localhost:27017/itdragonstu
Spring Data MongoDB 編程

Spring Data給我們提供了MongoTemplate類,極大的方便了我們的工作,但是若每個(gè)實(shí)體類都基于MongoTemplate重寫一套CRUD的實(shí)現(xiàn)類,似乎顯得有些笨重。于是我們可以將其簡(jiǎn)單的封裝一下。步驟如下

第一步:創(chuàng)建用戶實(shí)體類,其數(shù)據(jù)庫(kù)表名就是類名首字母小寫。
第二步:封裝MongoTemplate類,實(shí)現(xiàn)增刪改查,分頁(yè),排序,主鍵自增等常用功能。
第三步:創(chuàng)建封裝類的Bean管理類,針對(duì)不同的實(shí)體類,需要配置不同的bean。
第四步:創(chuàng)建測(cè)試類,測(cè)試:注冊(cè),更新,分頁(yè),排序,查詢用戶功能。

創(chuàng)建用戶實(shí)體類

用戶實(shí)體類有五個(gè)字段,除了主鍵ID,其他四個(gè)分別代表四個(gè)常用的類型(字符串,數(shù)字,對(duì)象,集合)。為了簡(jiǎn)化開(kāi)發(fā),實(shí)體類建議不實(shí)用@Document注解重命名User在MongoDB數(shù)據(jù)庫(kù)中的表名。
省略get/set方法和toString方法

import java.io.Serializable;
import java.util.ArrayList;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
 * 用戶實(shí)體類
 * @author itdragon
 */
//@Document(collection = "itdragon_user")  如果為了代碼的通用性,建議不要使用
public class User implements Serializable{
    
    private static final long serialVersionUID = 1L;
    @Id
    private Long id;
    private String name;
    private Integer age;
    private Address address;
    private ArrayList ability;
}

public class Address{
    private Long id;
    private String province;
    private String city;
}
封裝MongoTemplate類

SpringData提供的MongoTemplate類,極大的方便我們操作MongoDB數(shù)據(jù)庫(kù)??墒撬暮芏喾椒ǘ忌婕暗搅薈lass,和CollectionName。針對(duì)不同的實(shí)體類,我們需要重復(fù)寫不同的方法。這里,我們進(jìn)一步封裝,實(shí)現(xiàn)代碼的高可用。
實(shí)現(xiàn)的思路大致:將Class作為一個(gè)參數(shù),在初始化MongoTemplate的封裝類時(shí)賦值。這里有一個(gè)約束條件是:CollectionName是Class類名的首字母小寫。

import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;

@Repository
@SuppressWarnings({"unchecked", "rawtypes"})
public class ITDragonMongoHelper {
    
    @Autowired(required = false)
    private MongoTemplate mongoTemplate; 
    private Class entityClass;        // 實(shí)體類
    private String collectionName;    // 數(shù)據(jù)庫(kù)表名
    private String orderAscField;    // 升序字段
    private String orderDescField;    // 降序字段
    
    private static final String ID = "id";
    private static final String MONGODB_ID = "_id";
    
    public ITDragonMongoHelper() {
    }

    public ITDragonMongoHelper(Class entityClass) {
        this.entityClass = entityClass;
        this.collectionName = _getCollectionName();
    }

    public ITDragonMongoHelper(Class entityClass, String collectionName) {
        this.entityClass = entityClass;
        this.collectionName = collectionName;
    }
    
    /**
     * @Title save
     * @Description 通過(guò)Map創(chuàng)建實(shí)體類
     * @param object Map,無(wú)需自帶ID
     * @return
     */
    public Boolean save(Map requestArgs) {
        try {
            Object object = getEntityClass().newInstance();
            if (null == requestArgs.get(ID)) {
                requestArgs.put(ID, getNextId());
            }
            BeanUtils.populate(object, requestArgs);
            saveOrUpdate(object);
        } catch (Exception e) {
            e.printStackTrace();
            return Boolean.valueOf(false);
        }
        return Boolean.valueOf(true);
    }
    
    /**
     * @Title save
     * @Description 通過(guò)對(duì)象創(chuàng)建實(shí)體類
     * @param object 實(shí)體類,需自帶ID
     * @return
     */
    public Boolean saveOrUpdate(Object object) {
        try {
            this.mongoTemplate.save(object, this.collectionName);
        } catch (Exception e) {
            e.printStackTrace();
            return Boolean.valueOf(false);
        }
        return Boolean.valueOf(true);
    }
    
    /**
     * @Title update
     * @Description 通過(guò)Map更新實(shí)體類具體字段,可以減少更新出錯(cuò)字段,執(zhí)行的銷率更高,需嚴(yán)格要求數(shù)據(jù)結(jié)構(gòu)的正確性
     * @param requestArgs Map,需自帶ID, 形如:{id: idValue, name: nameValue, ....}
     * @return
     */
    public Boolean update(Map requestArgs) {
        Object id = requestArgs.get(ID);
        if (null == id) {
            return Boolean.valueOf(false);
        }
        try {
            Update updateObj = new Update();
            requestArgs.remove(ID);
            for (String key : requestArgs.keySet()) {
                updateObj.set(key, requestArgs.get(key));
            }
            findAndModify(Criteria.where(ID).is(id), updateObj);
        } catch (Exception e) {
            e.printStackTrace();
            return Boolean.valueOf(false);
        }
        return Boolean.valueOf(true);
    }
    
    /**
     * @Title find
     * @Description 根據(jù)查詢條件返回所有數(shù)據(jù),不推薦
     * @param criteria 查詢條件
     * @return
     */
    public List find(Criteria criteria) {
        Query query = new Query(criteria);
        _sort(query);
        return this.mongoTemplate.find(query, this.entityClass, this.collectionName);
    }
    
    /**
     * @Title find
     * @Description 根據(jù)查詢條件返回指定數(shù)量數(shù)據(jù)
     * @param criteria 查詢條件
     * @param pageSize 查詢數(shù)量
     * @return
     */
    public List find(Criteria criteria, Integer pageSize) {
        Query query = new Query(criteria).limit(pageSize.intValue());
        _sort(query);
        return this.mongoTemplate.find(query, this.entityClass, this.collectionName);
    }

    /**
     * @Title find
     * @Description 根據(jù)查詢條件分頁(yè)返回指定數(shù)量數(shù)據(jù)
     * @param criteria 查詢條件
     * @param pageSize 查詢數(shù)量
     * @param pageNumber 當(dāng)前頁(yè)數(shù)
     * @return
     */
    public List find(Criteria criteria, Integer pageSize, Integer pageNumber) {
        Query query = new Query(criteria).skip((pageNumber.intValue() - 1) * pageSize.intValue()).limit(pageSize.intValue());
        _sort(query);
        return this.mongoTemplate.find(query, this.entityClass, this.collectionName);
    }
    
    public Object findAndModify(Criteria criteria, Update update) {
        // 第一個(gè)參數(shù)是查詢條件,第二個(gè)參數(shù)是需要更新的字段,第三個(gè)參數(shù)是需要更新的對(duì)象,第四個(gè)參數(shù)是MongoDB數(shù)據(jù)庫(kù)中的表名
        return this.mongoTemplate.findAndModify(new Query(criteria), update, this.entityClass, this.collectionName);
    }
    
    /**
     * @Title findById
     * @Description 通過(guò)ID查詢數(shù)據(jù)
     * @param id 實(shí)體類ID
     * @return
     */
    public Object findById(Object id) {
        return this.mongoTemplate.findById(id, this.entityClass, this.collectionName);
    }
    
    /**
     * @Title findOne
     * @Description 通過(guò)查詢條件返回一條數(shù)據(jù)
     * @param id 實(shí)體類ID
     * @return
     */
    public Object findOne(Criteria criteria) {
        Query query = new Query(criteria).limit(1);
        _sort(query);
        return this.mongoTemplate.findOne(query, this.entityClass, this.collectionName);
    }
    
    // id自增長(zhǎng)
    public String getNextId() {
        return getNextId(getCollectionName());
    }

    public String getNextId(String seq_name) {
        String sequence_collection = "seq";
        String sequence_field = "seq";
        DBCollection seq = this.mongoTemplate.getCollection(sequence_collection);
        DBObject query = new BasicDBObject();
        query.put(MONGODB_ID, seq_name);
        DBObject change = new BasicDBObject(sequence_field, Integer.valueOf(1));
        DBObject update = new BasicDBObject("$inc", change);
        DBObject res = seq.findAndModify(query, new BasicDBObject(), new BasicDBObject(), false, update, true, true);
        return res.get(sequence_field).toString();
    }
    
    private void _sort(Query query) {
        if (null != this.orderAscField) {
            String[] fields = this.orderAscField.split(",");
            for (String field : fields) {
                if (ID.equals(field)) {
                    field = MONGODB_ID;
                }
                query.with(new Sort(Sort.Direction.ASC, new String[] { field }));
            }
        } else {
            if (null == this.orderDescField) {
                return;
            }
            String[] fields = this.orderDescField.split(",");
            for (String field : fields) {
                if (ID.equals(field)) {
                    field = MONGODB_ID;
                }
                query.with(new Sort(Sort.Direction.DESC, new String[] { field }));
            }
        }
    }
    
    // 獲取Mongodb數(shù)據(jù)庫(kù)中的表名,若表名不是實(shí)體類首字母小寫,則會(huì)影響后續(xù)操作
    private String _getCollectionName() {
        String className = this.entityClass.getName();
        Integer lastIndex = Integer.valueOf(className.lastIndexOf("."));
        className = className.substring(lastIndex.intValue() + 1);
        return StringUtils.uncapitalize(className);
    }
    
    public Class getEntityClass() {
        return entityClass;
    }
    public void setEntityClass(Class entityClass) {
        this.entityClass = entityClass;
    }
    public String getCollectionName() {
        return collectionName;
    }
    public void setCollectionName(String collectionName) {
        this.collectionName = collectionName;
    }
    public String getOrderAscField() {
        return orderAscField;
    }
    public void setOrderAscField(String orderAscField) {
        this.orderAscField = orderAscField;
    }
    public String getOrderDescField() {
        return orderDescField;
    }
    public void setOrderDescField(String orderDescField) {
        this.orderDescField = orderDescField;
    }
}
創(chuàng)建封裝類的Bean管理類

這里用Bean注解修飾的方法名和測(cè)試類中ITDragonMongoHelper 的變量名要保持一致。這樣才能具體知道是哪個(gè)實(shí)體類的數(shù)據(jù)操作。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.itdragon.pojo.User;
import com.itdragon.repository.ITDragonMongoHelper;

/**
 * ITDragonMongoHelper的bean配置管理類 
 * @author itdragon
 */
@Configuration
public class MongodbBeansConfig {
    
    @Bean // 該方法名很重要
    public ITDragonMongoHelper userMongoHelper() {
        return new ITDragonMongoHelper(User.class);
    }

}
MongoDB的測(cè)試類

主要測(cè)試MongoDB保存數(shù)據(jù),更新字符串,更新數(shù)值,更新對(duì)象(文檔),更新集合,分頁(yè)查詢幾個(gè)常用方法。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.test.context.junit4.SpringRunner;
import com.itdragon.StartApplication;
import com.itdragon.pojo.Address;
import com.itdragon.pojo.User;
import com.itdragon.repository.ITDragonMongoHelper;
/**
 * @RunWith    它是一個(gè)運(yùn)行器
 * @RunWith(SpringRunner.class) 表示讓測(cè)試運(yùn)行于Spring測(cè)試環(huán)境,不用啟動(dòng)spring容器即可使用Spring環(huán)境
 * @SpringBootTest(classes=StartApplication.class)  表示將StartApplication.class納入到測(cè)試環(huán)境中,若不加這個(gè)則提示bean找不到。
 * @author itdragon
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes=StartApplication.class)
public class SpringbootStudyApplicationTests {
    @Autowired
    private ITDragonMongoHelper userMongoHelper; // 命名規(guī)則:需和MongodbBeansConfig配置Bean的方法名一致
    @Test
    public void createUser() {
        System.out.println("^^^^^^^^^^^^^^^^^^^^^^createUser");
        for (int i = 0; i < 25; i++) {    // 插入25條數(shù)據(jù)
            User user = new User();
            user.setId(Long.valueOf(userMongoHelper.getNextId(User.class.getName())));
            user.setAge(25 + i);
            user.setName("itdragon-" + i);
            Address address = new Address();
            address.setId(Long.valueOf(userMongoHelper.getNextId(Address.class.getName()))); 
            address.setProvince("湖北省");
            address.setCity("武漢市");
            user.setAddress(address);
            ArrayList ability = new ArrayList<>();
            ability.add("Java");
            user.setAbility(ability);
            userMongoHelper.saveOrUpdate(user);
            System.out.println("user : " + user.toString());
        }
    }
    @Test
    public void updateUserName() {
        System.out.println("^^^^^^^^^^^^^^^^^^^^^^updateUserName");
        Map updateMap = new HashMap<>();
        // 查詢name為itdragon-1的數(shù)據(jù),將name修改為ITDragonBlog
        User user = (User) userMongoHelper.findOne(Criteria.where("name").is("itdragon-1"));
        if (null == user) {
            System.out.println("^^^^^^^^^^^^^^^^^^^^^^User non-existent");
            return ;
        }
        updateMap.put("id", user.getId());
        updateMap.put("name", "ITDragonBlog");
        userMongoHelper.update(updateMap);
    }
    @Test
    public void updateUserAddress() {
        System.out.println("^^^^^^^^^^^^^^^^^^^^^^updateUserAddress");
        Map updateMap = new HashMap<>();
        User user = (User) userMongoHelper.findOne(Criteria.where("name").is("itdragon-3"));
        if (null == user) {
            System.out.println("^^^^^^^^^^^^^^^^^^^^^^User non-existent");
            return ;
        }
        Address address = new Address();
        address.setId(Long.valueOf(userMongoHelper.getNextId(Address.class.getName()))); 
        address.setProvince("湖南省");
        address.setCity("長(zhǎng)沙");
        updateMap.put("id", user.getId());
        updateMap.put("address", address);
        userMongoHelper.update(updateMap);
    }
    @Test
    public void updateUserAbility() {
        System.out.println("^^^^^^^^^^^^^^^^^^^^^^updateUserAbility");
        Map updateMap = new HashMap<>();
        User user = (User) userMongoHelper.findOne(Criteria.where("name").is("itdragon-4"));
        if (null == user) {
            System.out.println("^^^^^^^^^^^^^^^^^^^^^^User non-existent");;
            return ;
        }
        ArrayList abilitys = user.getAbility();
        abilitys.add("APP");
        updateMap.put("id", user.getId());
        updateMap.put("ability", abilitys);
        userMongoHelper.update(updateMap);
    }
    @Test
    public void findUserPage() {
        System.out.println("^^^^^^^^^^^^^^^^^^^^^^findUserPage");
        userMongoHelper.setOrderAscField("age"); // 排序
        Integer pageSize = 5; // 每頁(yè)頁(yè)數(shù)
        Integer pageNumber = 1; // 當(dāng)前頁(yè)
        List users = userMongoHelper.find(Criteria.where("age").gt(25), pageSize, pageNumber); // 查詢age大于25的數(shù)據(jù)
        for (User user : users) {
            System.out.println("user : " + user.toString());
        }
    }
}
MongoDB開(kāi)發(fā)注意事項(xiàng)

MongoDB對(duì)表結(jié)構(gòu)要求不嚴(yán),方便了我們的開(kāi)發(fā),同時(shí)也提高了犯錯(cuò)率,特別是公司來(lái)了新同事,這顆地雷隨時(shí)都會(huì)爆炸。
第一點(diǎn): MongoDB通過(guò)key獲取value的值。而這個(gè)value可以是內(nèi)嵌的其他文檔。因?yàn)闆](méi)有主外鍵的概念,使用起來(lái)非常方便。若嵌套的文檔太深,在更新數(shù)據(jù)是,需要注意不能覆蓋原來(lái)的值。比如User表中的ability是一個(gè)集合,若傳一個(gè)字符串,依然可以更新成功,但已經(jīng)破壞了數(shù)據(jù)結(jié)構(gòu)。這是很多新手容易犯的錯(cuò)。

第二點(diǎn): 內(nèi)嵌的文檔屬性名最好不要重名。舉個(gè)例子,如果User表中的address對(duì)象,也有一個(gè)name的屬性。那么在后續(xù)寫代碼的過(guò)程中,極容易混淆。導(dǎo)致數(shù)據(jù)更新異常。

第三點(diǎn): 表的設(shè)計(jì)盡量做到扁平化,單表設(shè)計(jì)能有效提高數(shù)據(jù)庫(kù)的查詢銷率。

第四點(diǎn): 使用Mongoose約束數(shù)據(jù)結(jié)構(gòu),當(dāng)數(shù)據(jù)結(jié)構(gòu)不一致時(shí)操作失敗。

前兩點(diǎn)足以讓一些老輩程序員抓狂,讓新來(lái)的程序員懵圈。這也是很多開(kāi)發(fā)人員喜歡又討厭MongoDB的原因。

總結(jié)

1 MongoDB是最接近關(guān)系型數(shù)據(jù)的非關(guān)系型數(shù)據(jù)庫(kù)中的文檔型數(shù)據(jù)庫(kù)。

2 MongoDB支持非常豐富的查詢語(yǔ)句,功能強(qiáng)大,但容易犯錯(cuò)。

3 MongoDB表結(jié)構(gòu)的設(shè)計(jì)需謹(jǐn)慎,盡量減少嵌套層數(shù),各嵌套的文檔屬性名盡量避免相同。

參考文檔

MongoDB官方文檔: https://docs.mongodb.com

雙刃劍MongoDB的學(xué)習(xí)和避坑到這里就結(jié)束了,感謝大家的閱讀,歡迎點(diǎn)評(píng)。如果你覺(jué)得不錯(cuò),可以"推薦"一下。也可以"關(guān)注"我,獲得更多豐富的知識(shí)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/19206.html

相關(guān)文章

  • JS數(shù)據(jù)類型判斷--避坑指南

    摘要:測(cè)試構(gòu)造函數(shù)的屬性是否出現(xiàn)在對(duì)象的原型鏈中的任何位置。是全局方法時(shí)使用的原型方法可不填全局方法支持和添加到數(shù)據(jù)類型的原型中,不支持和的可以替代使用方式全局方法原型方法測(cè)試代碼原型方法不支持和,請(qǐng)用 1. 常用的typeof 對(duì)于array、object、null的判斷是不友好的,可以看下圖的執(zhí)行結(jié)果。 showImg(https://segmentfault.com/img/bVbqz...

    dayday_up 評(píng)論0 收藏0
  • 小程序webview使用避坑(因?yàn)殚_(kāi)發(fā)者配置域名錯(cuò)誤導(dǎo)致打開(kāi)失敗)

    摘要:解決方案對(duì)瀏覽器進(jìn)行判斷,如果是小程序官方判斷條件就跳過(guò)授權(quán)登錄。這樣就規(guī)避了訪問(wèn)非授權(quán)業(yè)務(wù)域名問(wèn)題。 問(wèn)題 小程序webview使用時(shí)出現(xiàn)了這樣的錯(cuò)誤提示 前提條件:嵌入的頁(yè)面域名已經(jīng)申請(qǐng)過(guò)業(yè)務(wù)域名 showImg(https://segmentfault.com/img/bVYr90?w=876&h=277); 然后訪問(wèn)報(bào)如下錯(cuò)誤 showImg(https://segmentfa...

    shengguo 評(píng)論0 收藏0
  • 小程序webview使用避坑(因?yàn)殚_(kāi)發(fā)者配置域名錯(cuò)誤導(dǎo)致打開(kāi)失?。?/b>

    摘要:解決方案對(duì)瀏覽器進(jìn)行判斷,如果是小程序官方判斷條件就跳過(guò)授權(quán)登錄。這樣就規(guī)避了訪問(wèn)非授權(quán)業(yè)務(wù)域名問(wèn)題。 問(wèn)題 小程序webview使用時(shí)出現(xiàn)了這樣的錯(cuò)誤提示 前提條件:嵌入的頁(yè)面域名已經(jīng)申請(qǐng)過(guò)業(yè)務(wù)域名 showImg(https://segmentfault.com/img/bVYr90?w=876&h=277); 然后訪問(wèn)報(bào)如下錯(cuò)誤 showImg(https://segmentfa...

    MonoLog 評(píng)論0 收藏0
  • 【ViewPager2避坑系列】瞬間暴增數(shù)個(gè)Fragment

    摘要:前言最近我在關(guān)注的使用,期間一直基于官方的調(diào)試,今天遇到一個(gè)奇葩的問(wèn)題,捉摸了半天最終找到原因,原來(lái)是中布局的問(wèn)題,事后感覺(jué)有必要分享一下這個(gè)過(guò)程,一來(lái)可以鞏固測(cè)量的知識(shí),二來(lái)希望大家能避開(kāi)這個(gè)坑閱讀指南代碼基于,看官老爺最好能下載前言 最近我在關(guān)注ViewPager2的使用,期間一直基于官方的Demo調(diào)試android-viewpager2,今天遇到一個(gè)奇葩的問(wèn)題,捉摸了半天最終找到原因,...

    番茄西紅柿 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<