Springboot整合Mongodb(含使用案例)

基础语法

插入

插入单条

// 插入一条数据到 "Books" 集合
db.Books.insertOne({
  title: "如何使用MongoDB",
  author: "IT小辉同学",
  year: 2023
})

插入多条数据

// 插入十条数据到 "Books" 集合
db.Books.insertMany([
  { title: "平凡的世界", author: "路遥", year: 1986 },
  { title: "呐喊", author: "鲁迅", year: 1923 },
  { title: "朝花夕拾", author: "鲁迅", year: 1928 },
  { title: "李自成", author: "王安忆", year: 2010 },
  { title: "寻找安详", author: "郭文斌", year: 2000 },
  { title: "推拿", author: "毕飞宇", year: 1999 },
  { title: "苏东坡传", author: "林语堂", year: 2015 },
  { title: "长安的荔枝", author: "马伯庸", year: 2021 },
  { title: "林清玄散文集", author: "林清玄", year: 1988 },
	 { title: "橘颂", author: "张炜", year: 2022 }
])

查询

//查询全部
db.Books.find()

//条件查询
db.Books.find({author:"鲁迅"})

//模糊查询 /xxx/  相当于like %xxx%
db.Books.find({author:{$regex:/同学/}})


// 字段显示 1:显示, 0 不显示
db.Books.find({}, { title: 1, author: 1, _id: 0 })


//排序
//正序:
db.Books.find().sort({year:1})
// 倒叙
db.Books.find().sort({year:-1})


// 限制条数
db.Books.find().limit(3)

修改

//查询第一个条件的数据,然后进行修改
db.Books.updateOne(
  { title: "橘颂", author: "张炜", year: 2022 },
  { $set: { year: 2023 } }
)

//修改多条
db.Books.updateMany(
  { title: "橘颂", author: "张炜", year: 1111 },
  { $set: { year: 2222 } }
)

删除

//单纯单条
db.Books.deleteOne(
  { title: "橘颂", author: "张炜", year: 2222 }
)


//删除多条
db.Books.deleteMany({ title: "橘颂"})

场景

Springboot整合

服务引入

1、引入依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>runtime</scope>
</dependency>
2、application.yaml配置
spring:
  data:
    mongodb:
      host: 127.0.0.1
      port: 27017
  # 如果有密码的,则需要配置密码
#      username: "admin"
#      password: "helloAdmin"
      database: my_db

各类场景

以Book类,作为演示案例

package com.walker.sample.mongdb.entity;

import com.walker.core.BasePage;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.List;

//文档名称:
@Document(collection = "Books")
@Data
public class Book {
    //    id
    @Id
    private String id;
    //    主题
    private String title;
    //    作者
    private String author;
    //    创建年份
    private Integer year;
    // 如果需要忽略的字段,则使用@Transient
}




新增数据

package com.walker.sample.easyexcel;

import cn.hutool.core.util.RandomUtil;
import com.walker.sample.mongdb.entity.Book;
import com.walker.sample.mongdb.utils.RandomNameUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Slf4j
@SpringBootTest
public class MongdbTest {

    // 1、引入template依赖
    @Autowired
    private MongoTemplate mongoTemplate;



    /**
    * author:walker
    * time: 2024/6/5
    * description:  插入数据
    */
    @Test
    public void addData(){
        List<Book> books = new ArrayList<>();
        Book book;
        // 2、构建数据
        for (int i = 0; i < 10000; i++) {
            book = new Book();
            book.setTitle(RandomNameUtil.getName()+"的书"+i);
            book.setAuthor(RandomNameUtil.getName());
            book.setYear(Integer.parseInt(RandomUtil.randomNumbers(5)));
            books.add(book);
        }
//     3、使用insert进行数据的插入
        mongoTemplate.insert(books,Book.class);
    }
}

插入数据结果:
image.png

但是可以发现,多了一个_class字段
作用:是为了方便处理Pojo中存在继承的情况,增加系统的扩展性的

具体可以参考:
MongoDB中_class字段的作用 - 上帝爱吃苹果-Soochow - 博客园

注意:

  • RandomNameUtil类:主要是用来创建名称
package com.walker.sample.mongdb.utils;

/**
 * 
 * 随机姓名
 **/
public class RandomNameUtil {
    // 姓氏池
    private static final String XING = "赵钱孙李周吴郑王";
    // 名字池
    private static final String MING = "三四五六七八建国强国富民少年强则中国强";

    public static String getName() {
        // 获取姓氏池的随机下标并随机获取一个姓氏
        char xing = XING.charAt((int) (Math.random() * XING.length()));

        // 创建一个可扩容字符串
        StringBuilder userName = new StringBuilder().append(xing);

        // 随机生成1或2,决定名字长度
        int mingLength = 1 + (int) (Math.random() * 2);
        int mingPoolLength = MING.length();

        for (int i = 0; i < mingLength; i++) {
            // 获取名字池的随机下标并随机获取一个名字字符并拼接
            char ming = MING.charAt((int) (Math.random() * mingPoolLength));
            userName.append(ming);
        }

        return userName.toString();
    }
}

分页查询

这个应该是我们实际应用中应用的比较多的了。
分别有多条件结合查询、排序、分页、总数查询等,那么下边将使用一个查询接口作为案例。

查询controller和逻辑
package com.walker.sample.mongdb;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.walker.core.TableDataInfo;
import com.walker.mongdb.utils.MyCriteria;
import com.walker.mongdb.utils.MyQuery;
import com.walker.sample.mongdb.entity.Book;
import com.walker.sample.mongdb.entity.BookForm;
import org.springframework.beans.factory.annotation.Autowired;
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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/book")
public class BookController {

    // 1、引入模板类
    @Autowired
    private MongoTemplate mongoTemplate;


    @GetMapping("/list")
    public TableDataInfo<Book> list(BookForm form) {

        // 2、创建查询类
        Query query = new Query();

        // 3、创建标准/条件
        Criteria criteria = new Criteria();
        // 因为是多条件结合,所以使用数组进行存储
        List<Criteria> criteriaList = new ArrayList<>();

//        模块查询title、
        if (StrUtil.isNotEmpty(form.getTitle())) {
            criteriaList.add(MyCriteria.like(Book::getTitle, form.getTitle()));
        }

//        精准查询year
        if (form.getYear() != null) {
            criteriaList.add(MyCriteria.is(Book::getYear, form.getYear()));
        }

//        根据year查询in
        if (CollUtil.isNotEmpty(form.getYears())) {
            criteriaList.add(MyCriteria.in(Book::getYear, form.getYears()));
        }

        // 将条件放入一个大的criteria中
        criteria.andOperator(criteriaList);
        // query添加criteria
        query.addCriteria(criteria);

//        计算总数
        Long count = mongoTemplate.count(query, Book.class);

//        设置跳页
        MyQuery.setPageNumAndSize(query, form.getPageNum(), form.getPageSize());

        // 排序
        MyQuery.sortAsc(query, Book::getYear);

//        分页查询
        List<Book> books = mongoTemplate.find(query, Book.class);
        return new TableDataInfo<>(count, books);
    }

}

涉及类

1、查询参数
用于请求参数的传递

package com.walker.sample.mongdb.entity;

import com.walker.core.BasePage;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.List;

@Data
public class BookForm extends BasePage{
//    主题
    private String title;
//    作者
    private String author;
//    创建年份
    private Integer year;
//    查询的years的条件
    @Transient
    private List<Integer> years;
}

  • 基础分页参数

统一封装,如果需要使用的参数直接继承即可

package com.walker.core;

import lombok.Data;

@Data
public class BasePage {
    /**
     * 页码
     */
    private Integer pageNum;
    /**
     * 页数
     */
    private Integer pageSize;
    
}

  • Criteria工具类
package com.walker.mongdb.utils;

import com.walker.mongdb.annotation.SFunction;
import org.springframework.data.mongodb.core.query.Criteria;

public class MyCriteria {


    /**
    * 模糊查询
    */
    public  static <T> Criteria like(SFunction<T> getField, Object value){
        String fieldName = FieldUtils.getFieldName(getField);
        return Criteria.where(fieldName).regex(".*?\\" + value + ".*");
    }

    /**
    * 精确查询
    */
    public static  <T> Criteria is(SFunction<T> getField,Object value){
        String fieldName = FieldUtils.getFieldName(getField);
        return Criteria.where(fieldName).is(value);
    }

    /**
    * 多个查询
    */
    public static  <T> Criteria in(SFunction<T> getField,Object value){
        String fieldName = FieldUtils.getFieldName(getField);
        return Criteria.where(fieldName).in(value);
    }
}

  • Query封装类
package com.walker.mongdb.utils;

import com.walker.mongdb.annotation.SFunction;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Query;

public class MyQuery {

    /**
    * 设置页码和页数
    */
    public static void setPageNumAndSize(Query query, Integer pageNum, Integer pageSize) {
        if(pageNum==null) pageNum=1;
        if(pageSize==null) pageSize=10;
        query.skip((long) (pageNum - 1) *pageSize);
        query.limit(pageSize);
    }

    /**
    * 正序
    */
    public static <T> void sortAsc(Query query, SFunction<T> getField) {
        String fieldName = FieldUtils.getFieldName(getField);
        Sort sort = Sort.by(Sort.Direction.ASC, fieldName);
        query.with(sort);
    }

    /**
    * 倒序
    */
    public static <T> void sortDesc(Query query, SFunction<T> getField) {
        String fieldName = FieldUtils.getFieldName(getField);
        Sort sort = Sort.by(Sort.Direction.DESC, fieldName);
        query.with(sort);
    }
}

  • 属性相关类,为了能够使用Stream方法去获取类的名称,减少魔法值的使用
package com.walker.mongdb.utils;

import com.walker.mongdb.annotation.SFunction;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class FieldUtils {
    private static final Map<SFunction<?>, Field> FUNCTION_CACHE = new ConcurrentHashMap<>();

    public static <T> String getFieldName(SFunction<T> function) {
        Field field = FieldUtils.getField(function);
        return field.getName();
    }

    public static <T> Field getField(SFunction<T> function) {
        return FUNCTION_CACHE.computeIfAbsent(function, FieldUtils::findField);
    }

    public static <T> Field findField(SFunction<T> function) {
        // 第1步 获取SerializedLambda
        final SerializedLambda serializedLambda = getSerializedLambda(function);
        // 第2步 implMethodName 即为Field对应的Getter方法名
        final String implClass = serializedLambda.getImplClass();
        final String implMethodName = serializedLambda.getImplMethodName();
        final String fieldName = convertToFieldName(implMethodName);
        // 第3步  Spring 中的反射工具类获取Class中定义的Field
        final Field field = getField(fieldName, serializedLambda);

        // 第4步 如果没有找到对应的字段应该抛出异常
        if (field == null) {
            throw new RuntimeException("No such class 「"+ implClass +"」 field 「" + fieldName + "」.");
        }

        return field;
    }

    static Field getField(String fieldName, SerializedLambda serializedLambda) {
        try {
            // 获取的Class是字符串,并且包名是“/”分割,需要替换成“.”,才能获取到对应的Class对象
            String declaredClass = serializedLambda.getImplClass().replace("/", ".");
            Class<?>aClass = Class.forName(declaredClass, false, ClassUtils.getDefaultClassLoader());
            return ReflectionUtils.findField(aClass, fieldName);
        }
        catch (ClassNotFoundException e) {
            throw new RuntimeException("get class field exception.", e);
        }
    }

    static String convertToFieldName(String getterMethodName) {
        // 获取方法名
        String prefix = null;
        if (getterMethodName.startsWith("get")) {
            prefix = "get";
        }
        else if (getterMethodName.startsWith("is")) {
            prefix = "is";
        }

        if (prefix == null) {
            throw new IllegalArgumentException("invalid getter method: " + getterMethodName);
        }

        // 截取get/is之后的字符串并转换首字母为小写
        return Introspector.decapitalize(getterMethodName.replace(prefix, ""));
    }

    static <T> SerializedLambda getSerializedLambda(SFunction<T> function) {
        try {
            Method method = function.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            return (SerializedLambda) method.invoke(function);
        }
        catch (Exception e) {
            throw new RuntimeException("get SerializedLambda exception.", e);
        }
    }
}

函数接口

package com.walker.mongdb.annotation;

import java.io.Serializable;

@FunctionalInterface
public interface SFunction<T> extends Serializable {
    Object apply(T t);
}

测试

具体就不演示了,可以使用各种参数进行测试
image.png

事务

确保你的MongoDB服务器版本至少是4.0以支持事务。此外,在使用事务时,请注意以下几点:

  • 你的MongoDB集合必须是事务兼容的。
  • 所有参与事务的集合必须在同一个数据库中。
  • 在事务方法中,不要直接使用MongoTemplate的execute方法来执行自定义操作。
  • 事务方法不能是非事务性的(即不能是@Transactional(propagation = Propagation.NOT_SUPPORTED))。
  • 如果使用MongoTemplate进行查询,确保查询是事务兼容的。

实现方案:
1、服务开启事务 使用@EnableTransactionManagement注解

package com.walker.sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//开启事务
@EnableTransactionManagement
@SpringBootApplication
public class WalkerSampleApplication {


    public static void main(String[] args) {
        SpringApplication.run(WalkerSampleApplication.class, args);
    }
}

忽略类中的字段

使用@Transient

package com.walker.sample.mongdb;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.List;

//文档名称:
@Document(collection = "Books")
@Data
public class Book {
    @Id
    private String id;
    private String title;
    private String author;
    private Integer year;
    @Transient
    private List<Integer> years;
}

参考:
https://blog.csdn.net/weixin_53742691/article/details/132418525

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/739726.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GitHub星标破千!斯坦福大学的284个机器学习小抄(漫画中文版)

说到人工智能必然要了解机器学习&#xff0c;从信息化软件&#xff0c;到电子商务&#xff0c;然后到高速发展互联网时代&#xff0c;到至今的云计算、大数据等&#xff0c;渗透到我们的生活、工作之中&#xff0c;在互联网的驱动下&#xff0c;人们更清晰的认识和使用数据&…

【事件总线】EventBus

文章目录 概述如何使用如何发布消息如何进行消息监听 来源 概述 事件总线是对发布-订阅模式&#xff08;观察者&#xff09;的一种实现&#xff0c;是一种集中式事件处理机制&#xff0c;允许不同的组件之间进行彼此通信而又不需要相互依赖&#xff0c;达到一种解耦的目的。 …

Maven下载安装、环境配置(超详细)(包括Windows、IDEA)

目录 一、引言 二、下载和安装 Maven &#xff08;1&#xff09;首先保证 Java 的环境是正常的。 1、电脑桌面上右击 " 此电脑 "&#xff0c;点击属性。 2、点击高级系统设置。 3、点击环境变量。 4、找到系统变量中的 Path。 5、点击新建&#xff0c;然后把…

Jmeter插件管理器,websocket协议,Jmeter连接数据库,测试报告的查看

目录 1、Jmeter插件管理器 1、Jmeter插件管理器用处&#xff1a;Jmeter发展并产生大量优秀的插件&#xff0c;比如取样器、性能监控的插件工具等。但要安装这些优秀的插件&#xff0c;需要先安装插件管理器。 2、插件的下载&#xff0c;从Availabale Plugins中选择&#xff…

论文翻译 | SELF-RAG: 学习通过自我反思来检索、生成和评估

Akari Asai, Zeqiu Wu, Yizhong Wang, Avirup Sil, Hannaneh Hajishirzi 华盛顿大学&#xff0c;IBM人工智能研究院 摘要 尽管大语言模型&#xff08;LLMs&#xff09;具有非凡的能力&#xff0c;但是它们经常产生不符合事实的响应&#xff0c;因为它们只依赖于它们封装的参数…

MySQL字典数据库设计与实现 ---项目实战

软件准备✍&#xff1a;Mysql与Navicat可视化命令大全 ----项目实战 文章前言部分 目录 一.摘要 二.设计内容 三.项目实现 一.摘要 本项目关注于字典数据库表结构的设计和数据管理。通过现有的sql文件&#xff0c;实现system_dict_type和system_dict_data两个数据表。随后…

汽车信息安全硬件讨论:SE vs HSM

目录 1.什么是Secure Element 2.芯片内置HSM和SE 3.未来HSM的发展 现在的智能网联汽车看起来像是一个连接万物的智能移动终端&#xff0c;它不仅可以与OEM云服务器通信接收OTA推送&#xff0c;还可以与手机蓝牙、Wifi交互完成远程汽车解锁、座舱内环境设置等等&#xff0c;借…

2024年通信技术与计算机科学国际学术会议(ICCTCS 2024)

2024年通信技术与计算机科学国际学术会议&#xff08;ICCTCS 2024&#xff09; 2024 International Academic Conference on Communication Technology and Computer Science&#xff08;ICCTCS 2024&#xff09; 会议简介&#xff1a; 2024年通信技术与计算机科学国际学术会议…

2023年零信任落地关键词:整合、身份、普及

2023年&#xff0c;全球企业纷纷加快了落地零信任的步伐。虽然落地的功能、落地的场景不尽相同&#xff0c;但企业对零信任的诉求、落地零信任的优先级却殊途同归&#xff0c;不同的零信任产品的应用场景也日益明晰。 全面整合和协同运行&#xff0c;是2023年企业用户对零信任…

LVGL使用GUI Guider配置STM32界面详细笔记教程

0、说明 接着前面几篇博客对LVGL的使用和介绍&#xff0c;这篇博客主要是使用和介绍快速配置LVGL图形界面编程的工具&#xff0c;GUI Guider。本文使用的工程代码&#xff0c;均是基于前几篇博客的基础上的&#xff0c;如需下载已配置好的LVGL-MCU工程环境&#xff0c;可通过如…

ANSYS Electronics 电磁场仿真工具下载安装,ANSYS Electronics强大的功能和灵活性

ANSYS Electronics无疑是一款在电磁场仿真领域表现卓越的软件工具。它凭借强大的功能和灵活性&#xff0c;帮助用户在产品设计阶段就能精确预测和优化电磁场性能&#xff0c;从而极大地降低了实际测试成本&#xff0c;并显著提升了产品的可靠性。 这款软件不仅在电子设计领域有…

标准立项 | 温室气体排放核算与报告要求 废油资源化企业

国内由于现有的废油再生企业规模较小&#xff0c;承担社会责任能力不强&#xff0c;在技术创新尤其是需要通过工程基础研究解决关键科技问题的创新积极性不高&#xff0c;由于经济成本的原因&#xff0c;多采用较落后的加工工艺&#xff0c;没有对废油中的特征污染物及毒害组分…

智慧在线医疗在线诊疗APP患者端+医生端音视频诊疗并开处方

智慧在线医疗&#xff1a;音视频诊疗新纪元 &#x1f310; 智慧医疗新篇章 随着科技的飞速发展&#xff0c;智慧医疗正逐步走进我们的生活。特别是在线医疗&#xff0c;凭借其便捷、高效的特点&#xff0c;已成为许多患者的首选。而其中的“智慧在线医疗患者端医生端音视频诊疗…

Databend 开源周报第 149 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 支持递归公共表…

Python数据分析-运用机器学习的方法对保险反欺诈的预测分析

一、研究背景及意义 保险欺诈不仅会造成暂时性的损失、增加公司的运营管理难度&#xff0c;而且对于合法的消费者来说负担了本不属于自身承担的风险&#xff0c;损害了其合法权益。因此&#xff0c;提高对车险欺诈的识别率并据此形成防范对策对提高保险公司的利润与维护消费者…

VERYCLOUD睿鸿股份亮相亚马逊云科技中国峰会2024

5月30日&#xff0c;为期两天的亚马逊云科技中国峰会在上海世博中心圆满落幕。 多位大咖现场分享&#xff0c;生成式AI时代的数据战略&#xff0c;企业级AI应用&#xff0c;最新技术、产品重磅发布&#xff0c;创新行业解决方案 …… 作为亚马逊云科技的生态合作伙伴&#x…

如何用IDEA(2024版)从github上拉取一个项目

前置要求&#xff1a; 确保你已经安装了 IntelliJ IDEA。确保你已经安装了 Git 工具并配置好了环境变量。确保你有一个 GitHub 账户&#xff0c;并且你想要克隆的仓库可以被你访问。 具体步骤&#xff1a; 1. 打开 IntelliJ IDEA 启动 IntelliJ IDEA。如果这是你第一次启动…

AIGC-商业设计大师班,商业设计全流程(22节课)

课程内容&#xff1a; 02.AIGC大师计划(百天磨炼&#xff0c;只为让你一次成为大师).mp4 03.这5个细心的翻译工具我想全部告诉你(感受不到的工具才是好工具),mp4 04.扎实的基础是成功的关键(汇聚精华指导新功能演示方法).mp4 05.AI绘画大师级十二体咒语书写(大师级起步).mp…

祛寒湿效果最好的40天到了!4个方法,助你把堵在体内的寒和湿排出去~

莫名犯困、身体沉重、没有食欲、嘴里发黏……遇上这些症状&#xff0c;很可能是你被寒湿偷袭了。 “热在三伏、冷在三九”&#xff0c;最热的时候&#xff0c;也是排湿祛寒最佳的时段&#xff0c;抓住三伏“冬病夏治”黄金40天&#xff0c;这段时间调理好了可以事半功倍&#x…

数智化浪潮下的零售品牌商品计划革新

在数字化和智能化交织的时代背景下&#xff0c;零售品牌的商品计划正在经历一场前所未有的革新。这场革新不仅改变了商品计划的方式和流程&#xff0c;更重塑了零售品牌的竞争格局和市场地位。 一、数智化&#xff1a;零售品牌的新引擎 在快速变化的市场环境中&#xff0c;零…