Spring中使用MongoTemplate訪問MongoDB


MongoDB是一款開源的文檔型數據庫。

NoSQL可以分為四大塊:

  • K-V類型:redis、MemberCached
  • 文檔型:MongoDB、Couchbase
  • 列存儲:Cassandra、HBase
  • 圖存儲:Neo4j

啟動MongoDB服務

通過Docker引擎啟動MongoDB服務。這里有MongoDB容器的相關說明

獲取鏡像

docker pull mongo

執行如上命令獲取最新的mongo鏡像。
image.png
image.png

運行MongoDB鏡像

docker run --name mongo -p 27017:27017 -v /Users/lucky/Documents/workspace/docker_mapping_volume/mongo:/data/db -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=admin -d mongo
  • --name mongo:指定容器名稱為mongo
  • -p 27017:27017:指定宿主機和容器的映射端口,[宿主機端口]:[容器端口]
  • -v [宿主機目錄]:[容器目錄]
  • -e 環境變量設置,設置賬號、密碼
  • -d 后台執行

查看運行的鏡像

docker ps

image.png

登陸到MongoDB容器中

docker exec -it mongo bash

通過shell連接MongoDB

mongo -u admin -p admin

image.png

初始化MongoDB的庫及權限

為項目創建對應的數據庫,以及有讀寫該庫權限的用戶。

創建庫

use springbucks;

使用use命令用來選擇數據庫,當我們在該庫上做操作時,MongoDB就會自動為我們創建數據庫。
image.png

創建用戶

db.createUser(
    {
      user: "springbucks",
      pwd: "springbucks",
      roles: [
         { role: "readWrite", db: "springbucks" }
      ]
} )

通過db.createUser來創建用戶,並指定用戶名密碼以及該用戶的權限。
image.png

查看用戶

show users

通過show users命令可以看到當前數據庫中創建的賬號信息。
image.png

Spring對MongoDB的支持

Spring對MongoDB的支持是通過Spring Data MongoDB這個項目來支持的,Spring Data MongoDB提供了MongoTemplate來對數據做增刪改查的操作。Spring Data MongoDB和Spring Data JPA類似,有對應的注解來標識。

注解

  • @Document
  • @Id

MongoTemplate

  • save / remove
  • Criteria / Query / Update

使用MongoTemplate操作MongoDB

自定義類型轉化類

業務中使用了joda-money這個類庫,我們在取數據的時候就需要將獲取到的數據類型Document進行轉換成我們需要的類型Money

package com.lucky.spring.converter;

import org.bson.Document;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;

/**
 * Created by zhangdd on 2020/8/8
 * <p>
 * 處理將Document 轉換成 Money
 */
public class MoneyReaderConverter implements Converter<Document, Money> {

    @Nullable
    @Override
    public Money convert(Document source) {
        //取數據
        Document money = (Document) source.get("money");
        //從獲取的數據中取對應的字段
        double amount = Double.parseDouble(money.getString("amount"));
        String currency = ((Document) money.get("currency")).getString("code");

        //將獲取的業務字段進行類型轉換
        return Money.of(CurrencyUnit.of(currency), amount);
    }
}

注入轉化Bean

類型轉換的功能已經做好,這里需要將該功能注入到容器中。

    @Bean
    public MongoCustomConversions mongoCustomConversions(){

        return new MongoCustomConversions(Arrays.asList(new MoneyReaderConverter()));
    }

說下思路吧。為什么會想到自定義這個轉換Bean。
既然Spring提供了MongoTemplate作為操作入口,那我們就從MongoTemplate開始看起。MongoTemplate同樣也是在自動配置模塊中,如下圖所示:
image.png
可以看到並排的包還有jpa、redis、couchbase等。

MongoDataAutoConfiguration

從左側類結構可以看出,MongoDataAutoConfiguration這個類方法不多。其中整個流程我們會用到的有如下這幾個

  • mongoTemplate()
  • mappingMongoConverter()
  • mongoCustomConversions()

image.png

MongoTemplate

既然MongoTemplate是入口,那就先找到MongoTemplate這個Bean的聲明地方。該方法需要一個MongoConverter

    @Bean
    @ConditionalOnMissingBean
    public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter converter) {
        return new MongoTemplate(mongoDbFactory, converter);
    }

MongoConverter

MongoConverter看名字像是和轉換有關的一個東西,如下圖是其類關系圖,可以看到其最后的實現類是MappingMongoConverter這個類。
image.png
如MongoDataAutoConfiguration類中定義的Bean已經實現了MappingMongoConverter這個類注入。

MappingMongoConverter

    @Bean
    @ConditionalOnMissingBean({MongoConverter.class})
    public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory, MongoMappingContext context, MongoCustomConversions conversions) {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
        mappingConverter.setCustomConversions(conversions);
        return mappingConverter;
    }

在mappingMongoConverter方法定義中,需要一個MongoCustomConversions參數。

MongoCustomConversions

    @Bean
    @ConditionalOnMissingBean
    public MongoCustomConversions mongoCustomConversions() {
        return new MongoCustomConversions(Collections.emptyList());
    }

可以看到在MongoCustomConversions 這個Bean的定義處,通過@ConditionalOnMissingBean注解說明:如果我們不自己定義該Bean,就會使用這段代碼生成的Bean。同時這個方法里傳的是一個空集合。所以 為什么會想到自定義這個轉換Bean 的原理就在這里了。Spring中很多Bean都是留了這樣的一個入口讓我們去可以自定義Bean。

保存查詢數據

    private void saveFindData() throws InterruptedException {
        Coffee espresso = Coffee.builder()
                .name("espresso")
                .price(Money.of(CurrencyUnit.of("CNY"), 20.0))
                .createTime(new Date())
                .updateTime(new Date())
                .build();
        mongoTemplate.save(espresso);
        log.info("Coffee {}", espresso);

        List<Coffee> list = mongoTemplate.find(
                Query.query(Criteria.where("name").is("espresso")), Coffee.class
        );
        log.info("find {} coffee", list.size());

        list.forEach(c->log.info("coffee {}",c));

        TimeUnit.SECONDS.sleep(1000);

    }

打印結果如下:

2020-08-08 09:56:59.163  INFO 50442 --- [           main] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:2, serverValue:4}] to localhost:27017
2020-08-08 09:56:59.232  INFO 50442 --- [           main] com.lucky.spring.Application             : Coffee Coffee(id=5f2e066b69ffe1c50ad58e1f, name=espresso, price=CNY 20.00, createTime=Sat Aug 08 09:56:59 CST 2020, updateTime=Sat Aug 08 09:56:59 CST 2020)
2020-08-08 09:56:59.277  INFO 50442 --- [           main] com.lucky.spring.Application             : find 1 coffee
2020-08-08 09:56:59.278  INFO 50442 --- [           main] com.lucky.spring.Application             : coffee Coffee(id=5f2e066b69ffe1c50ad58e1f, name=espresso, price=CNY 20.00, createTime=Sat Aug 08 09:56:59 CST 2020, updateTime=Sat Aug 08 09:56:59 CST 2020)

在MondoDB數據庫中查看結果:
image.png

更新數據

    private void updateData() {
        UpdateResult result = mongoTemplate.updateFirst(Query.query(Criteria.where("name").is("espresso")),
                new Update().set("price", Money.ofMajor(CurrencyUnit.of("CNY"), 30)).currentDate("updateTime"),
                Coffee.class);
        log.info("update result:{}", result.getMatchedCount());
    }

在MondoDB數據庫中查看結果:
image.png


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM