目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

Spring for MongoDB

常见数据库分类

Classification Name
Key-Value Redis、Memcached
Document MongoDB、CouchDB
Columnar HBase、Cassandra
Graph Neo4J

Docker 部署 MongoDB

 1# 拉取image
 2[root@master ~]# docker pull mongo
 3[root@master ~]# docker images | grep mongo
 4mongo	latest	a0e2e64ac939	3 weeks ago	64MB
 5
 6# 创建本地挂载目录
 7[root@master ~]# mkdir /data/mongodb -pv
 8
 9# 创建容器
10[root@master ~]# docker run --name mongo -v /data/mongod:/data/db -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=123456 -d mongo
110503c6157ef3b7e7cea96be9d193567543cfb52698ca294f10bb45ac886ddb28
12
13# 登录到MongoDB容器中
14[root@master ~]# docker exec -it mongo bash
15
16# 通过 Shell 连接 MongoDB
17root@752473287d58:/# mongo -u admin -p 123456
18---
19> 

Spring 对 MongoDB 的支持

 Spring Data 的目标就是在不失各个数据库特性的基础上增加一层相对统一的封装和抽象。
 通过 Spring Data MongoDB 项目。也提供了和 JdbcTemplate 类似的 MongoTemplate,通过 MongoTemplate 对数据进行 CRUD。同时 Spring Data MongoDB 也提供了像 JPA Repository 这样的 Repository 的支持。

注解

  • @Document:作用类似于 @Entity
  • @Id:文档的 Id

MongoTemplate

  • save / remove
  • Update / Query / Criteria

MongoTemplate

初始化 MongoDB 的库及权限

 1# 创建库
 2use springbucks;
 3
 4# 创建用户
 5db.createUser(
 6	{
 7		user: "springbucks",
 8		pwd: "springbucks",
 9		roles: [
10			{ role: "readWrite", db: "springbucks" }
11		]
12	}
13)

引入依赖

 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4	<modelVersion>4.0.0</modelVersion>
 5	<parent>
 6		<groupId>org.springframework.boot</groupId>
 7		<artifactId>spring-boot-starter-parent</artifactId>
 8		<version>2.1.2.RELEASE</version>
 9		<relativePath/> <!-- lookup parent from repository -->
10	</parent>
11	<groupId>geektime.spring.data</groupId>
12	<artifactId>mongo-demo</artifactId>
13	<version>0.0.1-SNAPSHOT</version>
14	<name>mongo-demo</name>
15	<description>Demo project for Spring Boot</description>
16
17	<properties>
18		<java.version>1.8</java.version>
19	</properties>
20
21	<dependencies>
22		<dependency>
23			<groupId>org.springframework.boot</groupId>
24			<artifactId>spring-boot-starter-data-mongodb</artifactId>
25		</dependency>
26
27		<dependency>
28			<groupId>org.joda</groupId>
29			<artifactId>joda-money</artifactId>
30			<version>RELEASE</version>
31		</dependency>
32
33		<dependency>
34			<groupId>org.projectlombok</groupId>
35			<artifactId>lombok</artifactId>
36			<optional>true</optional>
37		</dependency>
38		<dependency>
39			<groupId>org.springframework.boot</groupId>
40			<artifactId>spring-boot-starter-test</artifactId>
41			<scope>test</scope>
42		</dependency>
43	</dependencies>
44
45	<build>
46		<plugins>
47			<plugin>
48				<groupId>org.springframework.boot</groupId>
49				<artifactId>spring-boot-maven-plugin</artifactId>
50			</plugin>
51		</plugins>
52	</build>
53</project>

application.properties

1spring.data.mongodb.uri=mongodb://springbucks:springbucks@192.168.31.201:27017/springbucks
2spring.data.mongodb.username=admin
3spring.data.mongodb.password=123456

Coffee 实体类

 1package geektime.spring.data.mongodemo.model;
 2
 3import lombok.AllArgsConstructor;
 4import lombok.Builder;
 5import lombok.Data;
 6import lombok.NoArgsConstructor;
 7import org.joda.money.Money;
 8import org.springframework.data.annotation.Id;
 9import org.springframework.data.mongodb.core.mapping.Document;
10
11import java.util.Date;
12
13@Document //表明和 Coffee collection是对应的
14@Data
15@NoArgsConstructor
16@AllArgsConstructor
17@Builder
18public class Coffee {
19    @Id //会自动转换成MongoDB中的object id     org.springframework.data.annotation.Id;
20    private String id;
21    private String name;
22    private Money price;
23    private Date createTime;
24    private Date updateTime;
25}
26

MoneyReadConverter 类型转换处理类

 1package geektime.spring.data.mongodemo.converter;
 2
 3import org.bson.Document;
 4import org.joda.money.CurrencyUnit;
 5import org.joda.money.Money;
 6import org.springframework.core.convert.converter.Converter;
 7
 8public class MoneyReadConverter implements Converter<Document, Money> {
 9    /**
10     * 类型转换:用于处理 Document => Money
11     * @param source
12     * @return
13     */
14    @Override
15    public Money convert(Document source) {
16        Document money = (Document) source.get("money");
17        double amount = Double.parseDouble(money.getString("amount"));
18        String currency = ((Document) money.get("currency")).getString("code");
19        return Money.of(CurrencyUnit.of(currency), amount);
20    }
21}

启动类

 1package geektime.spring.data.mongodemo;
 2
 3import com.mongodb.client.result.UpdateResult;
 4import geektime.spring.data.mongodemo.converter.MoneyReadConverter;
 5import geektime.spring.data.mongodemo.model.Coffee;
 6import lombok.extern.slf4j.Slf4j;
 7import org.joda.money.CurrencyUnit;
 8import org.joda.money.Money;
 9import org.springframework.beans.factory.annotation.Autowired;
10import org.springframework.boot.ApplicationArguments;
11import org.springframework.boot.ApplicationRunner;
12import org.springframework.boot.SpringApplication;
13import org.springframework.boot.autoconfigure.SpringBootApplication;
14import org.springframework.context.annotation.Bean;
15import org.springframework.data.mongodb.core.MongoTemplate;
16import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
17import org.springframework.data.mongodb.core.query.Criteria;
18import org.springframework.data.mongodb.core.query.Query;
19import org.springframework.data.mongodb.core.query.Update;
20
21import java.util.Arrays;
22import java.util.Date;
23import java.util.List;
24
25import static org.springframework.data.mongodb.core.query.Criteria.where;
26import static org.springframework.data.mongodb.core.query.Query.query;
27
28@SpringBootApplication
29@Slf4j
30public class MongoDemoApplication implements ApplicationRunner {
31	@Autowired
32	private MongoTemplate mongoTemplate;
33
34	public static void main(String[] args) {
35		SpringApplication.run(MongoDemoApplication.class, args);
36	}
37
38	/**
39	 * 注入 MongoCustomConversions  用于类型转换
40	 * @return
41	 */
42	@Bean
43	public MongoCustomConversions mongoCustomConversions() {
44		return new MongoCustomConversions(Arrays.asList(new MoneyReadConverter()));
45	}
46
47	@Override
48	public void run(ApplicationArguments args) throws Exception {
49		//save : espresso
50		Coffee espresso = Coffee.builder()
51				.name("espresso")
52				.price(Money.of(CurrencyUnit.of("CNY"), 20.0))
53				.createTime(new Date())
54				.updateTime(new Date()).build();
55		Coffee saved = mongoTemplate.save(espresso);
56		log.info("Coffee {}", saved);
57		//Coffee Coffee(id=5e1c1985a99c044c4825a017, name=espresso, price=CNY 20.00, createTime=Mon Jan 13 15:17:25 CST 2020, updateTime=Mon Jan 13 15:17:25 CST 2020)
58
59		//Query
60		List<Coffee> list = mongoTemplate.find(
61				Query.query(Criteria.where("name").is("espresso")), Coffee.class);
62		log.info("Find {} Coffee", list.size());
63		//Find 1 Coffee
64		list.forEach(c -> log.info("Coffee {}", c));
65		//Coffee Coffee(id=5e1c1985a99c044c4825a017, name=espresso, price=CNY 20.00, createTime=Mon Jan 13 15:17:25 CST 2020, updateTime=Mon Jan 13 15:17:25 CST 2020)
66
67
68		//update
69		Thread.sleep(1000); // 为了看更新时间
70		UpdateResult result = mongoTemplate.updateFirst(query(where("name").is("espresso")),
71				new Update().set("price", Money.ofMajor(CurrencyUnit.of("CNY"), 30))
72						.currentDate("updateTime"),
73				Coffee.class);
74		log.info("Update Result: {}", result.getModifiedCount());
75		//Update Result: 1
76
77		//findById
78		Coffee updateOne = mongoTemplate.findById(saved.getId(), Coffee.class);
79		log.info("Update Result: {}", updateOne);
80		//Update Result: Coffee(id=5e1c214ba99c04325c0ae2b4, name=espresso, price=CNY 30.00, createTime=Mon Jan 13 15:50:35 CST 2020, updateTime=Mon Jan 13 15:50:37 CST 2020)
81		
82		//remove
83		mongoTemplate.remove(updateOne);
84	}
85}

登录容器中查看保存的文档信息

 1> use springbucks
 2switched to db springbucks
 3> show collections;
 4coffee
 5> db.coffee.find();
 6{ "_id" : ObjectId("5e1c1985a99c044c4825a017"), "name" : "espresso", "price" : { "money" : { "currency" : { "code" : "CNY", "numericCode" : 156, "decimalPlaces" : 2 }, "amount" : "20.00" } }, "createTime" : ISODate("2020-01-13T07:17:25.919Z"), "updateTime" : ISODate("2020-01-13T07:17:25.919Z"), "_class" : "geektime.spring.data.mongodemo.model.Coffee" }
 7
 8//删除espresso
 9> db.coffee.remove({"name":"espresso"});
10WriteResult({ "nRemoved" : 1 })
11> db.coffee.find();

MongoRepository

@EnableMongoRepositories
对应接⼝

  • MongoRepository<T, ID>
  • PagingAndSortingRepository<T, ID>
  • CrudRepository<T, ID>

引入依赖

 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4	<modelVersion>4.0.0</modelVersion>
 5	<parent>
 6		<groupId>org.springframework.boot</groupId>
 7		<artifactId>spring-boot-starter-parent</artifactId>
 8		<version>2.1.2.RELEASE</version>
 9		<relativePath/> <!-- lookup parent from repository -->
10	</parent>
11	<groupId>geektime.spring.data</groupId>
12	<artifactId>mongo-repository-demo</artifactId>
13	<version>0.0.1-SNAPSHOT</version>
14	<name>mongo-repository-demo</name>
15	<description>Demo project for Spring Boot</description>
16
17	<properties>
18		<java.version>1.8</java.version>
19	</properties>
20
21	<dependencies>
22		<dependency>
23			<groupId>org.springframework.boot</groupId>
24			<artifactId>spring-boot-starter-data-mongodb</artifactId>
25		</dependency>
26
27		<dependency>
28			<groupId>org.joda</groupId>
29			<artifactId>joda-money</artifactId>
30			<version>RELEASE</version>
31		</dependency>
32		<dependency>
33			<groupId>org.projectlombok</groupId>
34			<artifactId>lombok</artifactId>
35			<optional>true</optional>
36		</dependency>
37		<dependency>
38			<groupId>org.springframework.boot</groupId>
39			<artifactId>spring-boot-starter-test</artifactId>
40			<scope>test</scope>
41		</dependency>
42	</dependencies>
43
44	<build>
45		<plugins>
46			<plugin>
47				<groupId>org.springframework.boot</groupId>
48				<artifactId>spring-boot-maven-plugin</artifactId>
49			</plugin>
50		</plugins>
51	</build>
52</project>

application.properties

1spring.data.mongodb.uri=mongodb://springbucks:springbucks@192.168.31.201:27017/springbucks
2spring.data.mongodb.username=admin
3spring.data.mongodb.password=123456

Coffee

 1package geektime.spring.data.mongodemo.model;
 2
 3import lombok.AllArgsConstructor;
 4import lombok.Builder;
 5import lombok.Data;
 6import lombok.NoArgsConstructor;
 7import org.joda.money.Money;
 8import org.springframework.data.annotation.Id;
 9import org.springframework.data.mongodb.core.mapping.Document;
10
11import java.util.Date;
12
13@Document
14@Data
15@NoArgsConstructor
16@AllArgsConstructor
17@Builder
18public class Coffee {
19    @Id
20    private String id;
21    private String name;
22    private Money price;
23    private Date createTime;
24    private Date updateTime;
25}

MoneyReadConverter 类型转换处理类

 1package geektime.spring.data.mongodemo.converter;
 2
 3import org.bson.Document;
 4import org.joda.money.CurrencyUnit;
 5import org.joda.money.Money;
 6import org.springframework.core.convert.converter.Converter;
 7import org.springframework.stereotype.Component;
 8
 9@Component
10public class MoneyReadConverter implements Converter<Document, Money> {
11    @Override
12    public Money convert(Document source) {
13        Document money = (Document) source.get("money");
14        double amount = Double.parseDouble(money.getString("amount"));
15        String currency = ((Document) money.get("currency")).getString("code");
16        return Money.of(CurrencyUnit.of(currency), amount);
17    }
18}

CoffeeRepository

 1package geektime.spring.data.mongodemo.repository;
 2
 3import geektime.spring.data.mongodemo.model.Coffee;
 4import org.springframework.data.mongodb.repository.MongoRepository;
 5
 6import java.util.List;
 7
 8public interface CoffeeRepository extends MongoRepository<Coffee, String> {
 9    List<Coffee> findByName(String name);
10}

启动类

 1package geektime.spring.data.mongodemo;
 2
 3import geektime.spring.data.mongodemo.converter.MoneyReadConverter;
 4import geektime.spring.data.mongodemo.model.Coffee;
 5import geektime.spring.data.mongodemo.repository.CoffeeRepository;
 6import lombok.extern.slf4j.Slf4j;
 7import org.joda.money.CurrencyUnit;
 8import org.joda.money.Money;
 9import org.springframework.beans.factory.annotation.Autowired;
10import org.springframework.boot.CommandLineRunner;
11import org.springframework.boot.SpringApplication;
12import org.springframework.boot.autoconfigure.SpringBootApplication;
13import org.springframework.context.annotation.Bean;
14import org.springframework.data.domain.Sort;
15import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
16import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
17
18import java.util.Arrays;
19import java.util.Date;
20
21@Slf4j
22@SpringBootApplication
23@EnableMongoRepositories
24public class MongoRepositoryDemoApplication implements CommandLineRunner {
25	@Autowired
26	private CoffeeRepository coffeeRepository;
27
28	public static void main(String[] args) {
29		SpringApplication.run(MongoRepositoryDemoApplication.class, args);
30	}
31
32	@Bean
33	public MongoCustomConversions mongoCustomConversions() {
34		return new MongoCustomConversions(Arrays.asList(new MoneyReadConverter()));
35	}
36
37	@Override
38	public void run(String... args) throws Exception {
39		//init: espresso 、 latte
40		Coffee espresso = Coffee.builder()
41				.name("espresso")
42				.price(Money.of(CurrencyUnit.of("CNY"), 20.0))
43				.createTime(new Date())
44				.updateTime(new Date()).build();
45		Coffee latte = Coffee.builder()
46				.name("latte")
47				.price(Money.of(CurrencyUnit.of("CNY"), 30.0))
48				.createTime(new Date())
49				.updateTime(new Date()).build();
50		//insert
51		coffeeRepository.insert(Arrays.asList(espresso, latte));
52
53		//find
54		coffeeRepository.findAll(Sort.by("name"))
55				.forEach(c -> log.info("Saved Coffee {}", c));
56		//Saved Coffee Coffee(id=5e1c28b1a99c0451e446ac1d, name=espresso, price=CNY 20.00, createTime=Mon Jan 13 16:22:09 CST 2020, updateTime=Mon Jan 13 16:22:09 CST 2020)
57		//Saved Coffee Coffee(id=5e1c28b1a99c0451e446ac1e, name=latte, price=CNY 30.00, createTime=Mon Jan 13 16:22:09 CST 2020, updateTime=Mon Jan 13 16:22:09 CST 2020)
58
59		//update
60		Thread.sleep(1000);
61		latte.setPrice(Money.of(CurrencyUnit.of("CNY"), 35.0));
62		latte.setUpdateTime(new Date());
63		coffeeRepository.save(latte);
64		coffeeRepository.findByName("latte")
65				.forEach(c -> log.info("Coffee {}", c));
66		//Coffee Coffee(id=5e1c28b1a99c0451e446ac1e, name=latte, price=CNY 35.00, createTime=Mon Jan 13 16:22:09 CST 2020, updateTime=Mon Jan 13 16:22:10 CST 2020)
67
68		//delete
69		coffeeRepository.deleteAll();
70	}
71}

作者:Soulboy