让 MongoDB 的 CRUD 有 JPA 的味道

2021-10-14 10:39:59 浏览数 (1)

文末提供我整理的 SpringBoot 整合、操作 MongoDB 文档的下载方式!!!

早期文章

  • 使用 MongoTemplate 对 MongoDB 进行 CRUD
  • 省内存的 Excel 导入导出库还是得了解下它...
  • 后端程序员的 VUE 超简单入门笔记
  • 后端程序员的 ES6 超简单入门笔记
  • 看完即可上手 MyBatis-Plus
  • 奇怪的函数调用
  • 打造后台登录页面扫描工具
  • 一道有趣的 Java 基础题
  • Spring 拦截器流程及多个拦截器的顺序
  • Docker常用命令
  • Docker 使用 MySQL
  • JWT库生成Token的使用与原理
  • Java 项目中几个必不可少的小功能

上篇文章介绍了使用 MongoTemplate 对 MongoDB 进行 CRUD 的操作,那么接着上篇文章来继续介绍使用 MongoRepository 对 MongoDB 的 CRUD 的操作。

需要回顾上面文章的,可以点击该连接进行查看该链接 使用 MongoTemplate 对 MongoDB 进行 CRUD

来看一下 MongoDB 官网对 MongoDB 的简单描述,截图如下所示。

上篇文章中,使用 MongoTemplate 时只需要使用 @Autowired 将其注入就可以使用,而使用 MongoRepository 需要自己定义一个 Repository 接口,然后继承 MongoRepository 即可。

下面,接着来介绍 MongoRepository 的用法。

一、在 SpringBoot 中引入依赖

接着在上篇文章的项目来使用 MongoRepository 完成对 MongoDB 的 CRUD,如果没有看上篇使用 MongoTemplate 对 MongoDB 的 CRUD 的文章也没关系。只要创建一个 SpringBoot 项目,然后在 POM 文件中引入 MongoDB 的依赖坐标,即可将操作 MongoDB 的类库整合入 SpringBoot 项目当中,相关依赖如下:

代码语言:javascript复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

二、添加配置

引入依赖之后,如果 Maven 项目没有自动下载依赖,那么需要手动进行刷新一下,然后在 SpringBoot 的配置文件 application.yml(或 application.properties)中添加 MongoDB 的地址,如同使用 MySQL 一样,提供一个 uri 来告诉项目。配置文件如下:

代码语言:javascript复制
spring:
  data:
    mongodb:
      uri: mongodb://127.0.0.1:27017/test

在上面的 uri 中,test 指定了我们 Demo 中要操作的数据库。

三、定义对应 MongoDB 中集合的实体类

操作 MySQL 时,我们会将 MySQL 的表在项目中定义一个对应的实体类,操作 MongoDB 的集合也需要定义一个对应的实体类。这里定义一个 Student 的实体类作为 Demo 中的实体类来进行操作,定义如下:

代码语言:javascript复制
@Data
@Document("Student")
public class Student {

    @Id
    private String id;
    private String name;
    private Integer age;
    private String email;
}

在实体类上添加注解 @Document,@Document 中给出的是集合的名称。注解 @Id 会将该字段与 MongoDB 生成的 _id 进行关联。

在具体操作 MongoDB 时可以通过 MongoTemplate 来进行操作,也可以通过 MongoRepository 来进行操作。上篇文章介绍了 MongoTemplate 对 MongoDB 的 CRUD,本次将介绍如何使用 MongoRepository 来完成对 MongoDB 的 CRUD 操作。

以上的三步,和使用 MongoTemplate 的步骤是完全一样,下面的步骤则稍有差别。

四、定义实现 MongoRepository 接口的类

该步骤是使用 MongoTemplate 没有的一个步骤,我们需要定义一个 Repository 接口来继承 MongoRepository 接口,类似定义一个 Mapper 或一个 Dao,定义如下:

代码语言:javascript复制
public interface StudentRepository extends MongoRepository<Student, String> {

}

有了这个接口,我们就可以通过它来操作 MongoDB 数据库中的 Student 文档了。

这里简单介绍一下,MongoRepository 接口继承了 PagingAndSortingRepository 接口,该接口定义了 分页 和 排序 的功能,PagingAndSortingRepository 接口继承了 CrudRepository 接口,该接口定义了一组 CRUD 相关的方法。继承关系图如下:

看了上面的继承关系图,是不是有一种很熟悉的味道?那就是 Spring Data Jpa 的继承关系图与之类似,将 MongoRepository 改为 JpaRepository 来观察继承关系图,如下所示。

由此可以得知,使用 Repository 操作 MongoDB 的方法,同样可以用来操作 MySQL 数据库,反之亦然。如果在平时使用它操作 MySQL,可以很轻松的应用在 MongoDB 上。

五、使用 MongoRepository 完成 CRUD

定义了 StudentRepository 接口,那么在需要对 Student 进行操作的类中,只要将 StudentRepository 注入即可使用。

1.注入 StudentRepository 到使用类中

创建一个测试类,通过 @Autowired 将 StudentRepository 进行注入,代码如下:

代码语言:javascript复制
// 注入StudentRepository
@Autowired
private StudentRepository studentRepository;

2.添加操作

如果看过《使用 MongoTemplate 对 MongoDB 进行 CRUD》 文章的读者,可以先将上篇文章中生成的数据先删除,删除方式如下:

首先,选中 test 数据库,如下图:

接着,查看数据库中的集合,如下图:

最后,删除 Student 集合,如下图:

删除原来测试的数据,便于我们有一个干净的环境来让我们进行测试。

在注入 StudentRepository 后,我们即可在测试类中完成 CRUD 的操作,先来完成一个添加数据的操作,代码如下:

代码语言:javascript复制
/**
 * 添加操作
 */
@Test
void create() {

    for (int i = 0; i < 10; i   ) {
        Student student = new Student();
        student.setName("zhangsan"   i);
        student.setAge(30   i);
        student.setEmail(i   "999@qq.com");

        Student save = studentRepository.save(student);

        System.out.println(save);
    }
}

通过 StudentRepository 的 save 方法,即可完成数据的插入操作。

执行上面的测试代码后,我们通过 MongoDB 的客户端来查看一下我们添加的数据。首先使用 use 选择该数据库,然后使用 show collections 查看 test 数据库下的集合,可以看到在 test 数据库下自动创建了一个 Student 集合,如下图所示。

在我们执行上面的 save 方法之前,已经把 Student 集合删除了,也没有再创建 Student 集合。执行了上面的代码后,会自动创建 Student 集合,并且在 Student 集合中插入了 10 条文档。

3.查询集合中的所有记录

上面完成了文档数据插入的操作,现在通过 StudentRepository 来将其全部查出,代码如下:

代码语言:javascript复制
/**
 * 查询表中所有记录
 */
@Test
void findAll() {
    List<Student> all = studentRepository.findAll();

    all.forEach(System.out::println);
}

通过 StudentRepository 的 findAll 方法可以查询指定集合下的所有文档。

执行上面的代码后,在控制台会输出 Student 集合中的全部文档,输出内容如下所示。

代码语言:javascript复制
Student(id=6153405a080b7946ca278b3e, name=zhangsan0, age=30, email=0999@qq.com)
Student(id=6153405a080b7946ca278b3f, name=zhangsan1, age=31, email=1999@qq.com)
Student(id=6153405a080b7946ca278b40, name=zhangsan2, age=32, email=2999@qq.com)
Student(id=6153405a080b7946ca278b41, name=zhangsan3, age=33, email=3999@qq.com)
Student(id=6153405a080b7946ca278b42, name=zhangsan4, age=34, email=4999@qq.com)
Student(id=6153405a080b7946ca278b43, name=zhangsan5, age=35, email=5999@qq.com)
Student(id=6153405a080b7946ca278b44, name=zhangsan6, age=36, email=6999@qq.com)
Student(id=6153405a080b7946ca278b45, name=zhangsan7, age=37, email=7999@qq.com)
Student(id=6153405a080b7946ca278b46, name=zhangsan8, age=38, email=8999@qq.com)
Student(id=6153405a080b7946ca278b47, name=zhangsan9, age=39, email=9999@qq.com)

从输出中可以看出,MongoDB 为我们生成了 id,通过这个 id 我们可以唯一的确定一条数据。

4.通过 id 查询指定的文档

通常,我们在查询指定的某条数据时会通过 id 进行查询,在添加数据时,可以看到 MongoDB 为我们自动生成了 id,名为 _id,只要通过 MongoRepository 的 findById 方法(MongoTemplate 也有 findById 方法),并传入相应的 id 值即可查询指定的文档,代码如下:

代码语言:javascript复制
/**
 * id查询
 */
@Test
void findById() {
    Student student = studentRepository.findById("6153405a080b7946ca278b3e").get();
    System.out.println(student);
}

MongoRepository 的 findById 返回的是 Optional<Student> 类型,通过 get 方法可以获取到 Student 类型。

5.条件查询

MongoDB 支持非常强大的查询功能,这里简单的完成一个条件查询。代码如下:

代码语言:javascript复制
/**
 * 条件查询
 */
@Test
void findUserList() {
    // name = zhangsan0 and age = 30
    Student student = new Student();
    student.setName("zhangsan0");
    student.setAge(30);
    Example<Student> userExample = Example.of(student);
    List<Student> all = studentRepository.findAll(userExample);
    all.forEach(System.out::println);
}

上面的查询相当于如下 SQL 语句:

代码语言:javascript复制
select * from student where name = 'zhangsan0' and age = 30

除了通过 Example 来构建查询条件外,还可以通过在 StudentRepository 中定义接口的方式来进行查询,将上面的查询在 StudentRepository 中进行定义,代码如下:

代码语言:javascript复制
public interface StudentRepository extends MongoRepository<Student, String> {
    Student getStudentByNameAndAge(String name, Integer age);
}

有了上面的定义无需自己实现代码即可调用,调用方式如下:

代码语言:javascript复制
@Test
void findUserByCondition()
{
    Student zhangsan0 = studentRepository.getStudentByNameAndAge("zhangsan0", 30);

    System.out.println(zhangsan0);
}

Spring Data 提供的自动生成查询语句的功能只要根据约定好的规则,在接口中定义方法名即可。

6.模糊查询

MongoRepository 提供的模糊查询使用 ExampleMatcher 和 Example 即可完成模糊查询,代码如下:

代码语言:javascript复制
/**
 * 模糊查询
 */
@Test
void findLikeUserList() {
    // name like zhangsan and age = 30

    // 设置模糊查询匹配规则
    ExampleMatcher matcher = ExampleMatcher
            .matching()
            .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
            .withIgnoreCase();

    Student student = new Student();

    student.setName("s");
    student.setAge(30);

    Example<Student> studentExample = Example.of(student, matcher);

    List<Student> all = studentRepository.findAll(studentExample);

    all.forEach(System.out::println);
}

在 ExampleMatcher 中定义模糊查询的规则,Example 中提供查询的条件,即可完成模糊查询的功能。同样,模糊查询也可以使用 Spring Data 提供的规则来自动生成查询语句,这里不再进行演示。

7.分页查询

在 MySQL 中进行数据的分页查询,一般需要给接口传入页码和每页记录的条数,当然也需要传入一些查询条件。对于 MongoDB 而言,传入接口的数据也是一样的。

代码语言:javascript复制
@Test
void findPageUserList() {
    // 分页
    // 0 代表第一页
    Pageable pageable = PageRequest.of(1, 3);

    Page<Student> page = studentRepository.findAll(pageable);

    page.forEach(System.out::println);
    System.out.println(page.getTotalPages());
}

分页查询通过 Pageable 来完成,此处也类似于 MySQL 的 limit 的用法。上面的代码中,我们的分页每页显示 3 条,当前页是第 1 页。PageRequest.of 第一个参数传递是页数,只要传递页数后,它会自动计算从第几条记录开始取数据。

代码语言:javascript复制
Student(id=6153405a080b7946ca278b41, name=zhangsan3, age=33, email=3999@qq.com)
Student(id=6153405a080b7946ca278b42, name=zhangsan4, age=34, email=4999@qq.com)
Student(id=6153405a080b7946ca278b43, name=zhangsan5, age=35, email=5999@qq.com)
4

通过返回的 Page 对象,调用 getTotalPages 方法可以得到总的页数。

8.修改数据

修改数据时首先对数据进行查询,然后设置需要修改的值,再进行数据的更新。

代码语言:javascript复制
/**
 * 修改
 */
@Test
void updateUser() {
    Student student = studentRepository.findById("6153405a080b7946ca278b41").get();

    student.setName("wangwu");

    Student save = studentRepository.save(student);

    System.out.println(save);
}

在上面的代码中,使用 MongoRepository 的 save 方法即可完成数据的更新。在前面介绍插入时,使用的也是 save 方法。在调用 save 方法时,如果实体类中的 id 有值,则进行更新,如果没有值则进行插入操作。具体看其实现源码,源码如下:

代码语言:javascript复制
public <S extends T> S save(S entity) {
    Assert.notNull(entity, "Entity must not be null!");
    return this.entityInformation.isNew(entity) ? this.mongoOperations.insert(entity, this.entityInformation.getCollectionName()) : this.mongoOperations.save(entity, this.entityInformation.getCollectionName());
}

可以看到源码中使用 isNew 来判断是插入操作,还是更新操作。

接着来查看我们的数据是否被更新,如下图所示。

在更新字段时,更新哪个字段则对那个字段进行设置即可。

9.删除数据

删除操作直接使用 MongoRepository 提供的 deleteById 进行删除即可,代码如下:

代码语言:javascript复制
/**
 * 删除操作
 */
@Test
void deleteUser(){
    studentRepository.deleteById("6153405a080b7946ca278b41");
}

六、总结

MongoDB 已经被越来越多的使用,它适合于对大量的、无固定数据结构的数据进行存储。本文简单的介绍了通过使用 MongoRepository 来对 MongoDB 进行 CRUD 的操作,上篇文章介绍了 使用 MongoTemplate 对 MongoDB 进行 CRUD 的内容。大家可以对比学习。

0 人点赞