Spring Data套裝基礎之MongoDB
阿新 • • 發佈:2020-12-26
文章目錄
1. 簡介
Spring Data MongoDB屬於Spring Data套裝中的一個工具,提供了對MongoDB資料庫操作的封裝。
相對於直接使用MongoDB的驅動,Spring Data MongoDB可能更有優勢,不管是簡單還是複雜的操作。
對於簡單的操作Spring Data MongoDB甚至基本都不用寫什麼程式碼。
對於複雜的操作Spring Data MongoDB在抽象層做得更好,更方便維護。
2. 實體類
import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.Document; import java.util.List; @Document(collection = "student") public class Student { @Id private String id; private String name; private Integer age; @DBRef private List<Teacher> teachers; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public List<Teacher> getTeachers() { return teachers; } public void setTeachers(List<Teacher> teachers) { this.teachers = teachers; } @Override public String toString() { return "Student{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", age=" + age + ", teachers=" + teachers + '}'; } }
MongoDB的所有的文件都必須要有一個id。
Spring Data MongoDB咋確認類的哪一個欄位是id呢?
- 如果一個欄位有org.springframework.data.annotation.Id註解,它會被當做mongodb的id
- 如果沒有註解,但是欄位名稱是id,那麼它會被當做mongodb的id
註解 | 說明 |
---|---|
@Id | 標識文件ID,唯一 |
@DBRef | 一對多關係,不使用內嵌文件方式,而是分開儲存時使用,新增的時候並不會新增關聯文件,只會在查詢的時候根據id查詢 |
@Indexed | 在該欄位上建立索引,@Indexed(unique = true) |
@Document | 改類為MongoDB文件,@Document(collection=“mongodb”) |
@Transient | 不儲存欄位 |
@CompoundIndex | 複合索引,類上,@CompoundIndex(name = “age_idx”, def = “{‘name’: 1, ‘age’: -1}”),1表示升序,-1表示降序 |
@GeoSpatialIndexed | 欄位為地理資訊索引 |
@PersistenceConstructor | 建構函式,用於資料庫獲取的資料例項化為物件 |
3. Repository方式
Spring Data MongoDB是Spring Data套裝中的一個,那當然可以使用Repository的方式。
首先,如果使用註解還是需要@EnableMongoRepositories,指定要掃描Repository的包。
@Configuration
@EnableMongoRepositories(basePackages = {"vip.mycollege.mongodb.repository"})
public class MongodbConfig {
}
3.1 MongoRepository
基本操作,只需要繼承MongoRepository就可以了
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import vip.mycollege.mongodb.entity.Student;
public interface StudentRepository extends MongoRepository<Student,String> {
Page<Student> findByNameLike(String name, Pageable pageable);
}
不需要實現類,增刪改查都可以直接用,還可以通過遵循命名規範定義介面方法,那也不需要具體實現方法。
下面是測試程式碼:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringRunner;
import vip.mycollege.mongodb.entity.Student;
import vip.mycollege.mongodb.entity.Teacher;
import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentRepositoryTest {
@Resource
private StudentRepository studentRepository;
@Test
public void findByUserNameLike(){
PageRequest pageRequest = PageRequest.of(0, 5);
Page<Student> page = studentRepository.findByNameLike("tim", pageRequest);
System.out.println(page.getTotalPages());
page.getContent().forEach(System.out::println);
}
@Test
public void findAll(){
List<Student> students = studentRepository.findAll();
students.forEach(System.out::println);
}
@Test
public void saveAll(){
List<Student> users = getUsers(10);
studentRepository.saveAll(users);
}
}
3.2 QueryByExampleExecutor
當然也可以使用QueryByExampleExecutor方式
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
import vip.mycollege.mongodb.entity.Student;
public interface StudentQueryByExampleExecutor extends MongoRepository<Student,String>, QueryByExampleExecutor<Student> {
}
繼承MongoRepository是為了讓Spring Data為這個介面生成代理類。
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers;
import org.springframework.test.context.junit4.SpringRunner;
import vip.mycollege.mongodb.entity.Student;
import javax.annotation.Resource;
import java.util.Iterator;
@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentQueryByExampleExecutorTest {
@Resource
private StudentQueryByExampleExecutor studentQueryByExampleExecutor;
@Test
public void example(){
Student student = new Student();
student.setName("Amy");
Example<Student> example = Example.of(student);
// 查詢所有名字是Amy的學生
Iterator<Student> iterator = studentQueryByExampleExecutor.findAll(example).iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("-------------");
}
@Test
public void ExampleMatcher(){
Student student = new Student();
student.setName("a");
student.setAge(25);
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("age", GenericPropertyMatchers.exact())
.withMatcher("name", GenericPropertyMatchers.startsWith().ignoreCase());
Example<Student> example = Example.of(student,matcher);
// 查詢name以a或者A開頭,年齡為25的學生
Iterator<Student> iterator = studentQueryByExampleExecutor.findAll(example).iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
4. MongoTemplate方式
當然,如果想要更靈活的查詢,還可以使用MongoTemplate。
4.1 查詢文件方法
方法 | 說明 |
---|---|
find | 查詢指定文件列表 |
findAll | 查詢所有文件 |
findOne | 查詢第一個文件 |
findById | 通過ID查詢文件 |
findAndRemove | 查詢並刪除第一個文件 |
4.2 Query方法
註解 | 方法 | 說明 |
---|---|---|
Query | skip(int) | 跳過多少個文件,主要用於分頁 |
Query | with(Sort) | 排序 |
Query | limit(int) | 限制返回文件個數,主要用於分頁 |
Field | fields() | 定義結果中返回哪些欄位 |
Query | addCriteria(Criteria) | 在查詢中新增附件查詢條件 |
4.3 Criteria方法
方法 | 說明 |
---|---|
lt | 小於 |
gt | 大於 |
ne | 不等 |
in | in查詢 |
is | 欄位精確匹配,等於 |
lte | 小於等於 |
gte | 大於等於 |
all | 作用於陣列,全部包含,{ lang: { $all: [ “Python” , “Java” ] }} |
and | and關係 |
mod | 取模,mod m 等於n,db.cname.find( { status: { $mod: [4, 0]}}) |
nin | not in |
not | not |
size | 作用於陣列,陣列的大小滿足指定值 |
type | Creates a criterion using the $type operator |
regex | 正則表示式匹配 |
exists | 是否存在 |
elemMatch | 作用於陣列,陣列中所有元素匹配,db.cname.find({scores: {KaTeX parse error: Expected '}', got 'EOF' at end of input: elemMatch:{gte: 90, $lt: 100}}}) |
orOperator | or操作 |
norOperator | nor操作 |
andOperator | and操作 |
地理位置相關查詢:
方法 | 說明 |
---|---|
near | 某個點從近到遠的座標 |
within | 在指定的圓或者長方形內 |
withinSphere | 在指定的圓內 |
nearSphere | 在某個點附近 |
minDistance | 最小距離 |
maxDistance | 最大距離 |
4.4 示例
首先,需要配置MongoTemplate:
@Bean
public MongoClient mongoClient() {
return MongoClients.create("mongodb://localhost:27017");
}
public @Bean
MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoClient(), "test");
}
測試:
import com.mongodb.bulk.BulkWriteResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.BulkOperations;
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.test.context.junit4.SpringRunner;
import vip.mycollege.mongodb.entity.Student;
import javax.annotation.Resource;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MongoTemplateTest {
@Resource
private MongoTemplate mongoTemplate;
@Test
public void update(){
Criteria criteria = Criteria.where("name").is("tim");
Query query = Query.query(criteria);
Update update = Update.update("age", 35);
mongoTemplate.updateFirst(query, update, Student.class);
}
@Test
public void save(){
Student student = new Student();
student.setId("10001");
student.setAge(20);
student.setName("tim");
// 插入資料,如果id存在則更新
mongoTemplate.save(student);
}
@Test
public void insert(){
Student student = new Student();
student.setId("10002");
student.setName("allen");
student.setAge(25);
//插入資料,如果id已經存在則丟擲異常
mongoTemplate.insert(student);
}
@Test
public void remove(){
Student student = new Student();
student.setId("10003");
//刪除指定資料
mongoTemplate.remove(student);
}
@Test
public void bulk(){
//批量操作
BulkOperations bulkOperations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, Student.class);
Student student = new Student();
student.setAge(20);
bulkOperations.insert(student);
student = new Student();
student.setAge(100);
bulkOperations.insert(student);
BulkWriteResult result = bulkOperations.execute();
System.out.println(result.getInsertedCount());
}
@Test
public void find(){
Criteria criteria = Criteria.where("name").is("tim");
Query query = Query.query(criteria);
// 在student集合中查詢所有名字為tim的學生
List<Student> students = mongoTemplate.find(query, Student.class);
students.forEach(System.out::println);
}
@Test
public void query(){
// 查詢所有名字為tim並且年齡小於30的學生
Criteria criteria = Criteria.where("name").is("tim").and("age").gt(30);
Query query = Query.query(criteria);
List<Student> students = mongoTemplate.query(Student.class)
.matching(query)
.all();
students.forEach(System.out::println);
}
@Test
public void findById(){
// 查詢id為1的學生
Student student = mongoTemplate.findById("1", Student.class);
System.out.println(student);
}
@Test
public void findAll(){
// 獲取student集合中所有資料
List<Student> students = mongoTemplate.findAll(Student.class);
students.forEach(System.out::println);
}
@Test
public void collection(){
// 獲取所用集合名稱
mongoTemplate.getCollectionNames();
// 檢查集合是否存在
mongoTemplate.collectionExists(Student.class);
// 建立集合
mongoTemplate.createCollection(Student.class);
// 刪除集合
mongoTemplate.dropCollection(Student.class);
//獲取集合,不存在則建立
mongoTemplate.getCollection("hello");
}
}
save方法與insert方法的區別:
- insert只是插入資料,如果插入資料的id已經存在,則丟擲異常
- save可以插入或修改資料,如果插入資料id已經存在,則執行更新操作
5. 文件資料