Spring for MongoDB
常见数据库分类
Classification | Name |
---|---|
Key-Value | Redis、Memcached |
Document | MongoDB、CouchDB |
Columnar | HBase、Cassandra |
Graph | Neo4J |
Docker部署MongoDB
# 拉取image
[root@master ~]# docker pull mongo
[root@master ~]# docker images | grep mongo
mongo latest a0e2e64ac939 3 weeks ago 64MB
# 创建本地挂载目录
[root@master ~]# mkdir /data/mongodb -pv
# 创建容器
[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
0503c6157ef3b7e7cea96be9d193567543cfb52698ca294f10bb45ac886ddb28
# 登录到MongoDB容器中
[root@master ~]# docker exec -it mongo bash
# 通过 Shell 连接 MongoDB
root@752473287d58:/# mongo -u admin -p 123456
---
>
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的库及权限
# 创建库
use springbucks;
# 创建用户
db.createUser(
{
user: "springbucks",
pwd: "springbucks",
roles: [
{ role: "readWrite", db: "springbucks" }
]
}
)
引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>geektime.spring.data</groupId>
<artifactId>mongo-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mongo-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.joda</groupId>
<artifactId>joda-money</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.data.mongodb.uri=mongodb://springbucks:springbucks@192.168.31.201:27017/springbucks
spring.data.mongodb.username=admin
spring.data.mongodb.password=123456
Coffee 实体类
package geektime.spring.data.mongodemo.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.joda.money.Money;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
@Document //表明和 Coffee collection是对应的
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Coffee {
@Id //会自动转换成MongoDB中的object id org.springframework.data.annotation.Id;
private String id;
private String name;
private Money price;
private Date createTime;
private Date updateTime;
}
MoneyReadConverter 类型转换处理类
package geektime.spring.data.mongodemo.converter;
import org.bson.Document;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.springframework.core.convert.converter.Converter;
public class MoneyReadConverter implements Converter<Document, Money> {
/**
* 类型转换:用于处理 Document => Money
* @param source
* @return
*/
@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);
}
}
启动类
package geektime.spring.data.mongodemo;
import com.mongodb.client.result.UpdateResult;
import geektime.spring.data.mongodemo.converter.MoneyReadConverter;
import geektime.spring.data.mongodemo.model.Coffee;
import lombok.extern.slf4j.Slf4j;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
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 java.util.Arrays;
import java.util.Date;
import java.util.List;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
@SpringBootApplication
@Slf4j
public class MongoDemoApplication implements ApplicationRunner {
@Autowired
private MongoTemplate mongoTemplate;
public static void main(String[] args) {
SpringApplication.run(MongoDemoApplication.class, args);
}
/**
* 注入 MongoCustomConversions 用于类型转换
* @return
*/
@Bean
public MongoCustomConversions mongoCustomConversions() {
return new MongoCustomConversions(Arrays.asList(new MoneyReadConverter()));
}
@Override
public void run(ApplicationArguments args) throws Exception {
//save : espresso
Coffee espresso = Coffee.builder()
.name("espresso")
.price(Money.of(CurrencyUnit.of("CNY"), 20.0))
.createTime(new Date())
.updateTime(new Date()).build();
Coffee saved = mongoTemplate.save(espresso);
log.info("Coffee {}", saved);
//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)
//Query
List<Coffee> list = mongoTemplate.find(
Query.query(Criteria.where("name").is("espresso")), Coffee.class);
log.info("Find {} Coffee", list.size());
//Find 1 Coffee
list.forEach(c -> log.info("Coffee {}", c));
//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)
//update
Thread.sleep(1000); // 为了看更新时间
UpdateResult result = mongoTemplate.updateFirst(query(where("name").is("espresso")),
new Update().set("price", Money.ofMajor(CurrencyUnit.of("CNY"), 30))
.currentDate("updateTime"),
Coffee.class);
log.info("Update Result: {}", result.getModifiedCount());
//Update Result: 1
//findById
Coffee updateOne = mongoTemplate.findById(saved.getId(), Coffee.class);
log.info("Update Result: {}", updateOne);
//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)
//remove
mongoTemplate.remove(updateOne);
}
}
登录容器中查看保存的文档信息
> use springbucks
switched to db springbucks
> show collections;
coffee
> db.coffee.find();
{ "_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" }
//删除espresso
> db.coffee.remove({"name":"espresso"});
WriteResult({ "nRemoved" : 1 })
> db.coffee.find();
MongoRepository
@EnableMongoRepositories
对应接⼝
- MongoRepository<T, ID>
- PagingAndSortingRepository<T, ID>
- CrudRepository<T, ID>
引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>geektime.spring.data</groupId>
<artifactId>mongo-repository-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mongo-repository-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.joda</groupId>
<artifactId>joda-money</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.data.mongodb.uri=mongodb://springbucks:springbucks@192.168.31.201:27017/springbucks
spring.data.mongodb.username=admin
spring.data.mongodb.password=123456
Coffee
package geektime.spring.data.mongodemo.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.joda.money.Money;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
@Document
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Coffee {
@Id
private String id;
private String name;
private Money price;
private Date createTime;
private Date updateTime;
}
MoneyReadConverter 类型转换处理类
package geektime.spring.data.mongodemo.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.stereotype.Component;
@Component
public class MoneyReadConverter implements Converter<Document, Money> {
@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);
}
}
CoffeeRepository
package geektime.spring.data.mongodemo.repository;
import geektime.spring.data.mongodemo.model.Coffee;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
public interface CoffeeRepository extends MongoRepository<Coffee, String> {
List<Coffee> findByName(String name);
}
启动类
package geektime.spring.data.mongodemo;
import geektime.spring.data.mongodemo.converter.MoneyReadConverter;
import geektime.spring.data.mongodemo.model.Coffee;
import geektime.spring.data.mongodemo.repository.CoffeeRepository;
import lombok.extern.slf4j.Slf4j;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import java.util.Arrays;
import java.util.Date;
@Slf4j
@SpringBootApplication
@EnableMongoRepositories
public class MongoRepositoryDemoApplication implements CommandLineRunner {
@Autowired
private CoffeeRepository coffeeRepository;
public static void main(String[] args) {
SpringApplication.run(MongoRepositoryDemoApplication.class, args);
}
@Bean
public MongoCustomConversions mongoCustomConversions() {
return new MongoCustomConversions(Arrays.asList(new MoneyReadConverter()));
}
@Override
public void run(String... args) throws Exception {
//init: espresso 、 latte
Coffee espresso = Coffee.builder()
.name("espresso")
.price(Money.of(CurrencyUnit.of("CNY"), 20.0))
.createTime(new Date())
.updateTime(new Date()).build();
Coffee latte = Coffee.builder()
.name("latte")
.price(Money.of(CurrencyUnit.of("CNY"), 30.0))
.createTime(new Date())
.updateTime(new Date()).build();
//insert
coffeeRepository.insert(Arrays.asList(espresso, latte));
//find
coffeeRepository.findAll(Sort.by("name"))
.forEach(c -> log.info("Saved Coffee {}", c));
//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)
//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)
//update
Thread.sleep(1000);
latte.setPrice(Money.of(CurrencyUnit.of("CNY"), 35.0));
latte.setUpdateTime(new Date());
coffeeRepository.save(latte);
coffeeRepository.findByName("latte")
.forEach(c -> log.info("Coffee {}", c));
//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)
//delete
coffeeRepository.deleteAll();
}
}