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.1port: 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@Idprivate 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依赖@Autowiredprivate MongoTemplate mongoTemplate;/*** author:walker* time: 2024/6/5* description:  插入数据*/@Testpublic 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、引入模板类@Autowiredprivate 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()));}//        精准查询yearif (form.getYear() != null) {criteriaList.add(MyCriteria.is(Book::getYear, form.getYear()));}//        根据year查询inif (CollUtil.isNotEmpty(form.getYears())) {criteriaList.add(MyCriteria.in(Book::getYear, form.getYears()));}// 将条件放入一个大的criteria中criteria.andOperator(criteriaList);// query添加criteriaquery.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的条件@Transientprivate 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步 获取SerializedLambdafinal 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中定义的Fieldfinal 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 {@Idprivate String id;private String title;private String author;private Integer year;@Transientprivate List<Integer> years;
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

期末考试的成绩怎么发?

随着学期末的临近&#xff0c;我们又迎来了向家长通报学生成绩的关键时刻。下面是一份成绩群发的全新指南&#xff0c;让我们一起高效而温馨地完成这项任务&#xff01; 1.选择沟通渠道&#xff1a; - 邮件与短信各有优势。邮件更适合提供详尽的成绩分析和评语&#xff0c;而短…

【Nginx】Nginx安装及简单使用

https://www.bilibili.com/video/BV1F5411J7vK https://www.kuangstudy.com/bbs/1353634800149213186 https://stonecoding.net/system/nginx/nginx.html https://blog.csdn.net/qq_40492693/article/details/124453090 Nginx 是一个高性能的 HTTP 和反向代理 Web 服务器。其特…

vim操作小诀窍:快速多行添加注释

在使用vim编译python代码的时候&#xff0c;经常碰到需要将一段代码注释的情况&#xff0c;每次都要按“向下” “向左”按钮&#xff0c;将光标移到句首&#xff0c;然后再键入#井号键。如果行数较多&#xff0c;则操作相当繁琐。 vim里面有将一段文字前面加#注释的方法&#…

LLVM——安装多版本LLVM和Clang并切换使用(Ubuntu)

1、描述 本机&#xff08;Ubuntu22&#xff09;已经安装了LLVM-14&#xff0c;但是需要使用LLVM-12。安装LLVM-12和Clang-12并切换使用。 2、过程 安装LLVM-12和Clang-12。 sudo apt-get install llvm-12 sudo apt-get install clang-12 【注】运行 sudo apt-get install ll…

【备考指南】数据分析备考资料

很多考生朋友在报名前后&#xff0c;一直不知道需要怎么备考&#xff0c;这里给大家盘点一下资料&#xff0c;希望对你有用&#xff1a; 1、cda数据分析师的硬技能与软技能&#xff1a;https://edu.cda.cn/goods/show/3604 2、机器学习驱动的金融风控&#xff1a;https://edu.…

windowns server2016服务器配置php调用powerpoint COM组件

解决问题&#xff1a;windowns server2016服务器配置php调用powerpoint COM组件 环境&#xff1a; windows server2016 宝塔&#xff08;nginxmysqlphp7.2&#xff09; IIS 搭建宝塔&#xff1a; 下载地址&#xff1a;https://www.bt.cn/download/windows.html ​ 安装使用&…

春招面试面经总结篇

目录 前言一&#xff0c;算法篇1.1 平拍数组1.2 括号匹配1.3 打家劫舍1.4 删除最少使字符串平衡1.5 爬楼梯 二&#xff0c;数据结构篇2.1 二叉树2.2 链表 三&#xff0c;HTML篇3.1 H5新的语义标签3.2 href和src 四&#xff0c;CSS篇4.1 居中4.2 父元素塌陷解决4.3 外边距塌陷4.…

藏在十九页PPT里的“海合安之道”

6月6日&#xff0c;成立仅仅两年多的海合安集团亮相2024中国主题公园战略营销峰会&#xff0c;作为本届峰会最年轻的主题公园企业&#xff0c;备受行业关注。 海合安集团成立于2021年&#xff0c;为亚洲最大私募投资基金之一的安博凯投资基金&#xff08;MBK Partners&#xf…

开发一个python工具,pdf转图片,并且截成单个图片,然后修整没用的白边及循环遍历文件夹全量压缩图片

今天推荐一键款本人开发的pdf转单张图片并截取没有用的白边工具 一、开发背景&#xff1a; 业务需要将一个pdf文件展示在前端显示&#xff0c;但是基于各种原因&#xff0c;放弃了h5使用插件展示 原因有多个&#xff0c;文件资源太大加载太慢、pdf展示兼容性问题、pdf展示效果…

Git 常用命令,一文全搞懂

注意&#xff1a;每一次切换分支的时候&#xff0c;本地代码都会自动跟随改变&#xff0c;不需要重新pull,除非有人更新了代码 git remote add origin 地址 连接远程仓库 git clone 地址 克隆项目到本地 git init 更新本地隐藏文件初始化仓库 git add . 代…

周记-2024第25周

2024.6.12-2024.6.23 本周有什么新的收获和进步&#xff0c;总结一下。 记忆力下降的很快&#xff0c;即便是本周的日记&#xff0c;我在回看时&#xff0c;也发现很多都已经忘了。时间也是一样&#xff0c;如果时间日志上没有记录某个时间段做了什么&#xff0c;我发现第二天…

PayPal账号冻结原因及应对

在跨境领域&#xff0c;PayPal这种收款方式&#xff0c;可以说是如影随形&#xff0c;是很多跨境卖家和外贸B2B商户首选的收款方式&#xff0c;就和我们在国内使用某宝、某信一样常见。但使用PayPal收款&#xff0c;最头疼的就是遇到账户冻结以及各种审核&#xff0c;那出现这个…

python例子:翻译器(简单)

作品介绍 作品名称&#xff1a;翻译器 开发环境&#xff1a;PyCharm 2023.3.4 python3.7 用到的库&#xff1a;PyQt5、translate、sys 作品简介&#xff1a;“输入内容”输入要翻译的中文内容&#xff0c;“选择语言”选择要翻译的语种&#xff0c;最后点击“开始翻译”&a…

大模型中的Lang chain是什么意思

LangChain 是一个开源框架&#xff0c;旨在简化构建和操作由大型语言模型 (LLMs) 驱动的应用程序。它提供了一套工具和抽象&#xff0c;帮助开发者将多个语言模型集成到应用程序中&#xff0c;并简化了模型的管理、交互和扩展。 LangChain 的核心概念 Chain&#xff08;链&…

基于轨迹加权的混合离线强化学习数据集

写在前面&#xff1a; 这篇论文阅读已经同步到我的博客网站&#xff0c;若需更优的阅读体验&#xff0c;请前往https://mainjaylai.github.io/Blog/blog/paper/trajectory-dataset进行浏览 摘要 大多数离线强化学习&#xff08;RL&#xff09;算法通过最大化目标策略的期望性…

品牌出海!独立站不仅是方向,而是成为跨境电商主流了

近些年&#xff0c;随着跨境电商3.0品牌出海和本土化时代的到来&#xff0c;独立站成为品牌出海的必备渠道和关键胜负手&#xff01; 搭建独立站作为品牌本土化的最好展示载体&#xff0c;独立的品牌包装与产品页面&#xff0c;能够更好讲述品牌故事&#xff0c;因而得以快速发…

【计算机网络体系结构】计算机网络体系结构实验-www服务器配置管理实验

一、实验内容 www服务器配置管理&#xff0c; wireshark数据包分析 二、实验目的 1. 了解WWW服务的体系结构与工作原理&#xff0c;掌握利用Microsoft的IIS实现WWW服务的基本配置&#xff0c;掌握WEB站点的管理 2. 利用Wireshark抓取http数据包进行分析。运行软件Wireshark…

怎么把CSV文件数据导入MySQL并自动生成表

MySQL MySQL是一个流行的关系型数据库管理系统(RDBMS),使用结构化查询语言(SQL)进行数据库管理。它是基于客户端/服务器架构的开源软件,由瑞典的MySQL AB公司开发,现在属于甲骨文公司(Oracle Corporation)。MySQL支持多种操作系统,包括各种版本的Unix、Linux和Window…

java基于ssm+jsp 师生交流平台

1 管理员登录 管理员输入个人的账号、密码登录系统&#xff0c;这时候系统的数据库就会在进行查找相关的信息&#xff0c;如果我们输入的账号、密码不正确&#xff0c;数据库就会提示出错误的信息提示&#xff0c;同时会提示管理员重新输入自己的账号、密码&#xff0c;直到账…

焦化超低排平台组成部分

焦化行业作为重工业的重要组成部分&#xff0c;其环保问题一直备受关注。近年来&#xff0c;随着环保意识的提升和技术的不断进步&#xff0c;朗观视觉焦化超低排平台应运而生&#xff0c;成为推动焦化行业绿色发展的重要力量。本文将深入剖析焦化超低排平台的组成部分&#xf…