MongoDB基础学习总结及SpringBoot项目中的整合

news2024/11/9 0:45:12

前言

MongoDB 如今是最流行的 NoSQL 数据库之一,被广泛应用于各行各业中,很多创业公司数据库选型就直接使用了 MongoDB。MongoDB一经推出就受到了广大社区的热爱,可以说是对程序员最友好的一种数据库之一,下面主要是笔者在平常的学习中对这个数据库学习的一点小总结,包括基础知识以及它同Mysql一样作为数据库在SpringBoot项目中的技术整合流程梳理。

MongoDB简介

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。它可以应用于各种规模的企业、各个行业以及各类应用程序的开源的非关系型数据库。

MongoDB的数据结构非常灵活,它可以随着应用程序的发展而灵活地更新。与此同时,它也为开发人员提供了许多传统数据库的功能:二级索引、完整的查询系统及数据一致性等。可以说是最像关系型数据库的非关系型数据库。MongoDB能够使企业更加具有灵活性和可扩展性,无论是创业公司、互联网企业或者是传统企业都可以通过MongoDB 来创建新的应用。

MongoDB具备高可扩展性、高性能和高可用性等非关系型数据库的特性,可以从单服务器部署扩展到大型、复杂的多数据中心架构。利用内存计算的优势, MongoDB 能够提供高性能的数据读写操作。 MongoDB的本地复制和自动故障转移功能使应用程序具有企业级的可靠性和操作灵活性。

MongoDB的特点

MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。相比其它的数据库,MongoDB具有如下特点:

1、易扩展性,MongoDB使用分片技术对数据进行扩展,MongoDB能自动分片、自动转移分片里面的数据块,去掉了关系型数据库的关系型特性,数据之间没有关系。让每一个服务器里面存储的数据都是一样大小。这样就非常容易扩展。

2、高性能,Mongo非常适合实时的插入,保留了关系型数据库即时查询的能力,并具备网站实时数据存储所需的复制及高度伸缩性。

3、高伸缩性,Mongo非常适合由数十或数百台服务器组成的数据库,Mongo的路线图中已经包含对MapReduce引擎的内置支持。

4、存储动态性,相较于传统的数据库当要增加一个属性值的时,对表的改动比较大,mongodb的面向文档的形式可以使其属性值轻意的增加和删除。而原来的关系型数据库要实现这个需要有很多的属性表来支持。

5、速度与持久性,MongoDB通过驱动调用写入时,可以立即得到返回得到成功的结果(即使是报错),这样让写入的速度更加快,当然会有一定的不安全性,完全依赖网络。

MongoDB与传统SQL的按结构对比

SQL 术语MongoDB 术语说明
DataBaseDataBase数据库
TableCollection数据库表/集合
RowDocument数据记录行/文档
ColumnField数据字段/域
indexindex索引
Table joinsMongoDB 不支持
primary keyprimary key主键,MongoDB自动将 _id字段设置为主键

如上表所示:MongoDB 和关系数据库一样有库的概念,一个MongoDB 可以有多个数据库, MongoDB 中的集合就相当于我们关系数据库中的表,文档就相当于关系数据库中的数据行,域就相当于关系数据库中的列, MongoDB也支持各种索引有唯一主键,但不支持表连接查询。

MongoDB的安装

MonggoDB支持以下Windows,Linux等平台。同时也提供了C、C++、C# / .NET、Erlang、Java、Ruby、Go等语言的驱动客户端。

直接找到MongDB官网进行下载即可,可以选择自己对应的平台的压缩包zip或者msi文件进行下载即可。

 Windows这里不详述,用手下就行了。这里仅以Centos 7系统为例,演示MongoDB的安装。

另外需要注意的是:在安装前需要安装libcurl、openssl等依赖包。命令如下:sudo yum install libcurl openssl

Step1:下载

这里使用wget在线下载安装,也可以通过上面的下载地址,手动下载安装包。

# 1.下载
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-6.0.5.tgz 
# 2.解压
tar -zxvf mongodb-linux-x86_64-rhel70-6.0.5.tgz 
# 3.将解压包拷贝到指定目录
mv mongodb-linux-x86_64-rhel70-6.0.5.tgz /usr/local/mongodb  

Step2:创建数据库目录

默认情况下 MongoDB 启动后会初始化以下两个目录:

  • 数据存储目录:/var/lib/mongodb

  • 日志文件目录:/var/log/mongodb

所以,在启动前先创建这两个目录,命令如下:

sudo mkdir -p /var/lib/mongo
sudo mkdir -p /var/log/mongodbsudo 
chown 777 /var/lib/mongo     # 设置权限
sudo chown 777 /var/log/mongodb   # 设置权限

Step3:创建配置文件

MongoDB的bin目录下创建一个mongodb.conf 文件,增加如下配置:

#touch mongodb.conf
port=27017                           #端口
bind_ip=0.0.0.0                      #默认是127.0.0.1dbpath=/var/lib/mongo/               #数据库存放logpath=/var/log/mongodb/mongod.log  #日志文件
fork=true                            #设置后台运行#auth=true                           #开启认证

MongoDB默认没有配置文件,需要我们手动创建配置文件。建议使用自定义配置文件,而不是默认配置。bind_ip 设置为0.0.0.0,否则Mongo服务只能本地连接,远程服务器会连接不上。

Step4:启动MongDB服务

进入MongoDB安装目录下的bin目录通过命令启动:

mongod --config mongodb.conf

如果没有配置这个mongodb.conf文件也可以通过mongo本地启动。

打开 /var/log/mongodb/mongod.log 文件看到以下信息,说明启动成功。

# tail -10f /var/log/mongodb/mongod.log
2023-04-14T08:31:09.925+0800 I  NETWORK  [listener] Listening on /tmp/mongodb-27017.sock
2023-04-14T08:31:09.925+0800 I  NETWORK  [listener] Listening on 127.0.0.1
2023-04-14T08:31:09.925+0800 I  NETWORK  [listener] waiting for connections on port 27017

如果要停止 mongodb 可以使用以下命令:

mongod --config mongodb.conf --shutdown

MongoDB的基本操作

MongoDB Shell 是 MongoDB 自带的交互式 Javascript shell,用来对 MongoDB 进行操作和管理的交互式环境。因此只要我们服务开启了,直接通过mongo就能进入数据库客户端操作了。

[root@VM-12-4-centos ~]# mongo
MongoDB shell version v6.0.5
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("dd2d1fd6-2fcf-4f35-a871-b75697e93434") }
MongoDB server version: 6.0.5
>

基本操作

MongoDB可以说是最像关系数据库的非关系数据库。一些命令和Mysql 比较类似。比如show databases查看数据库,use database 切换数据库等。

# 查询数据库
show databases
# 切换数据库,
use test
# 查询当前数据库下面的集合
show collections
# 创建集合
db.createCollection("集合名称")
# 删除集合
db.集合名称.drop()
# 删除数据库
db.dropDatabase() //首先要通过use切换到当前的数据库

MongoDB没有创建数据库的命令,提供了use 命令切换数据库,如果数据库不存在,则切换后,创建完机会后会自动创建数据库。如果你要创建一个新的数据库,使用use 命令切换到新数据库,然后创建collection 即可。

有了集合数据后,就可以对MongoDB 的集合中数据进行增删改查等操作。MongoDB的数据结构和 JSON 基本一样。所有存储在集合中的数据都是 BSON 格式存储(一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称)。

新增(insert)

插入数据之前,需要创建collocation,这里使用db.createCollection("``userinfo``")命令创建了userinfo集合。

#新增一条数据
db.userinfo.insert({name:"三",age:25,gander:"男",address:'湖北'})
#新增多条数据
db.userinfo.insert([{name:"李四",age:25,gander:"男",address:'湖南'},{name:"王五",age:16,gander:"女",address:'浙江'}])

删除(delete)

在 MongoDB 中,remove 和 deleteOne 以及 deleteMany 都用于删除文档记录。但是,remove 函数返回的删除的结果的 WriteResult,而 delete 函数返回的是 bson 格式。

其中 remove 是根据参数 justOne 来判断是删除所有匹配的文档记录还是仅仅删除一条匹配的文档记录,默认是删除所有的匹配的记录。

deleteOne 函数仅仅删除一条匹配的文档记录,而 deleteMany 函数是删除所有的匹配的文档记录。

# 全部删除
db.userinfo.deleteMany({})
# 删除age为25的一条数据
db.inventory.deleteOne( { age:25} )
# 删除年龄为16岁的全部数据
db.userinfo.deleteMany({age:16})
# remove 移除
db.userinfo.remove({'name':'王五'})

根据MongoDB的官方说明,remove() 方法已经过时了,现在官方推荐使用 deleteOne() 和 deleteMany() 方法。

修改(update)

MongoDB提供了 update() 方法来更新集合中的数据。update() 方法使用比较复杂,语法格式如下所示:

db.collection.update(   <query>,   <update>,   {     upsert: <boolean>,     multi: <boolean>,     writeConcern: <document>   })

参数说明:

  • query : update的查询条件,类似sql update语句后where查询条件。

  • update : update的对象和一些更新的操作(如$,$inc...)等,也可以理解为sql update查询内set 部分。

  • upsert : 可选,这个参数的意思是,如果不存在update的记录是否插入,true为插入,默认是false 不插入。

  • multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。

  • writeConcern :可选,抛出异常的级别。

下面,我们通过 update() 方法来更新一条数据:

db.userinfo.update({'name':'王五'},{$set:{'address':'汉阳'}})

上面的示例中,通过update()方法将姓名(name)为‘王五’的用户的住址信息(address)改为‘汉阳’。

查询(find)

MongoDB 使用 find() 方法查询显示文档数据。语法格式如下:db.collection.find(query, projection)

  • query 指定查询条件,类似sql select语句后的where条件,

  • projection 为指定返回的键。默认返回文档中所有键值。

# 查询全部
db.userinfo.find()
# pretty() 方法以Json格式化显示所有文档。db.userinfo.find().pretty()
# 查询一条数据
db.userinfo.findOne()
# 限制返回条数
db.userinfo.find().limit(1)

运算符

我们在查询数据的时候,经常会在查询条件中遇到条件判断的情况。如:查询年龄大于18岁的所有人员。同样,MongoDB中也提供类类似的条件运算符,具体有如下几个:

  • (>) 大于 - $gt

  • (<) 小于 - $lt

  • (>=) 大于等于 - $gte

  • (<= ) 小于等于 - $lte

# 查询年龄大于20的全部人员
db.userinfo.find({age:{$gt:20}})

MongoDB同样也有运算符$in,查询是否在某个集合中,类似sql 中的in关键字。使用方式如下:

db.userinfo.find({age:{$in:[16,20]}})

排序&分页

MongoDB提供了sort() 方法对数据进行排序,通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列。语法格式为:db.collection.find().sort({key:1})

# 按年龄升序
db.userinfo.find({}).sort({age:1})
# 按年龄降序
db.userinfo.find({}).sort({age:-1})

MongoDB提供了skip()方法来跳过指定数量的数据,skip方法同样接受一个数字参数作为跳过的记录条数。语法格式为:db.collection.find().limit(NUMBER).skip(NUMBER)

#分页查询,跳过20条查询10条
​​​​​​​db.userinfo.find({}).sort({age:1}).skip(20).limit(10)

如上所示,通过skip() 和limit() 方法,即可实现数据分页查询的功能。

Spring Boot 整合MongoDB

Spring Boot提供了MongoDB的组件:spring-boot-starter-data-mongodb ,它是 Spring Data 的一个子模块。熟悉Spring Boot的朋友应该知道,Redis、Elasticsearch、JPA等数据操作组件都在Spring Data下。所以,在Spring Boot中操作mongodb和操作其他的数据库基本是一样的。

spring-boot-starter-data-mongodb 核心功能是映射 POJO 到 Mongo的DBCollection 中的文档,并且提供 Repository 风格数据访问层。spring-bootstarter-data-mongodb 除了继承 Spring Data 的通用功能外,针对 MongoDB 的特性开发了很多定制的功能,让我们使用 Spring Boot 操作 MongoDB 更加简便。

Spring Boot 操作 MongoDB 有两种比较流行的使用方法,一种是将 MongoTemplate 直接注入使用,一种是继承 MongoRepository, MongoRepository 内置了很多方法可直接使用。下面分别来介绍它们的使用。

MongoTemplate

MongoTemplate 提供了非常多的操作 MongoDB 方法,MongoTemplate 实现了MongoOperations 接口,此接口定义了众多的操作方法如 find、 findAndModify、findOne、 insert、 remove、 save、 update and updateMulti 等。并提供了Query、 Criteria and Update 等流式 API。

添加依赖

首先创建Spring Boot项目spring-boot-starter-mongodb,在 pom 包里面添加 spring-boot-starter-data-mongodb 包引用,示例代码如下:

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-mongodb</artifactId></dependency>

添加MongoDB连接配置

修改application.yml配置文件,添加Mongo连接配置,具体如下:

spring:
   data:
    mongodb:
      uri: mongodb://localhost:27017/news

mongodb默认没有账号密码,IP+端口+数据库就可以连接成功。如果mongodb配置了有账号密码,那连接字符串则需要增加相应的账号密码:

spring:
   data:
    mongodb:
      uri: mongodb://username:password@192.168.78.101:27017/news

此外,如果MongoDB采用集群部署的方式,可以使用集群的配置方式,具体如下:

spring:
   data:
    mongodb:
      uri: mongodb://user:pwd@ip1:port1,ip2:port2/database

如果需要打印数据库执行日志的话,可以加上下面的日志打印配置:

#打印mongoDB执行日志
logging: 
  level:
    org.springframework.data.mongodb.core: DEBUG

然后就可以准备相关信息数据操作了。

准备一个mongoDB集合文档

这里提前准备数据库的文档数据。

创建其对应的实体类

package com.yy.entity;
​
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.models.auth.In;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
​
import java.io.Serializable;
​
/**
 * @author young
 * @date 2022/12/5 21:24
 * @description: 政策文档对应类
 */
@Data
@Document(collection = "policy")
@ApiModel(value = "policy文档", description = "对应的政策信息类")
public class Policy implements Serializable {
    private static final long serialVersionUID = -7636268378874627600L;
    @Id
    @ApiModelProperty("政策文档id")
    private String ids;
​
    @ApiModelProperty("政策文档大标题")
    private String bigTitle;
​
    @ApiModelProperty("政策文档子标题")
    private String childTitle;
​
    @ApiModelProperty("政策文档内容")
    private String content;
​
    @ApiModelProperty("政策文档自定义id")
    private Integer id;
    
    @ApiModelProperty("政策文档点击量")
    private Integer hits;
    
    @ApiModelProperty("政策文档创建时间")
    private String creatTime;
}

在IDEA中如果SpringBoot项目中导入mongoDB的相关集成依赖后,可以通过注解标名数据库集合对应的实体类信息。

 然后和Mysql数据库不同的是,它不需要我们准备常规的Dao层,直接创建Service进行数据操作即可。

创建Service接口和实现类

package com.yy.service;
​
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.yy.dto.NewsParam;
import com.yy.dto.PolicyParam;
import com.yy.entity.Net;
import com.yy.entity.Policy;
​
import java.util.List;
​
/**
 * @author young
 * @date 2022/12/5 21:58
 * @description:
 */
public interface PolicyService {
    /**
     * 查询所有的Policy文档信息
     * @return
     */
    List<Policy> findAll();
​
    /**
     * 根据自定义id查询对应的Policy文档信息
     * @param id
     * @return
     */
    Policy findById(Integer id);
​
    /**
     * 查询所有大标题
     * @return
     */
    List<Policy> bigTitleList();
    /**
     * 根据子标题查询对应的Policy文档信息
     * @param childTitle
     * @return
     */
    Policy findByChild(String childTitle);
​
    /**
     * 统计大标题数
     * @param bigTitle
     * @return
     */
    long countByType(String bigTitle);
​
    /**
     * 分页查询
     * @param data
     * @return
     */
    List<Policy> findByPage(NewsParam data);
​
    /**
     * 新增一个信息
     * @param policy
     * @return
     */
    Policy save(Policy policy);
​
    /**
     * 通过子标题更新内容信息
     * @param childTitle
     * @param content
     * @return
     */
    UpdateResult update(String childTitle, String content);
​
    /**
     * 子标题模糊查询
     * @param childTitle
     * @return
     */
    List<Policy> findLike(String childTitle);
​
    /**
     * 删除集合数据库中的一条信息
     * @param id
     * @return
     */
    DeleteResult delete(Integer id);
​
    /**
     * 管理员界面的政策信息分页查询
     * @param data
     * @return
     */
    List<Policy> findAdmin(PolicyParam data);
}

这里主要是实现一些基本的增删改查操作,通过MongoTamplate来实现操作逻辑。

package com.yy.service.impl;
​
import cn.hutool.core.date.DateUtil;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.yy.dto.NewsParam;
import com.yy.dto.PolicyParam;
import com.yy.entity.Policy;
import com.yy.service.PolicyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
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.stereotype.Service;
import org.springframework.util.Assert;
​
import java.time.LocalDateTime;
import java.util.List;
import java.util.regex.Pattern;
​
/**
 * @author young
 * @date 2022/12/5 22:01
 * @description:
 */
@Service
public class PolicyServiceImpl implements PolicyService {
    public static final String BIG_TITLE = "bigTitle";
    public static final String CHILD_TITLE = "childTitle";
    @Autowired
    private MongoTemplate mongoTemplate;
​
    @Override
    public List<Policy> findAll() {
        return mongoTemplate.findAll(Policy.class);
    }
​
    @Override
    public Policy findById(Integer id) {
        return mongoTemplate.findOne(new Query(Criteria.where("_id").is(id)), Policy.class);
    }
​
    @Override
    public List<Policy> bigTitleList() {
        return mongoTemplate.findDistinct(BIG_TITLE, Policy.class, Policy.class);
    }
​
    @Override
    public Policy findByChild(String childTitle) {
        return mongoTemplate.findOne(new Query(Criteria.where("childTitle").is(childTitle)), Policy.class);
    }
​
    @Override
    public List<Policy> findByPage(NewsParam data) {
        Assert.notNull(data, "该对象为空");
        Query query = new Query(Criteria.where(BIG_TITLE).is(data.getType()));
        query.with(Sort.by(Sort.Direction.ASC, "_id"));
        query.skip(data.getCurrent() - 1).limit(data.getSize());
        return mongoTemplate.find(query, Policy.class);
    }
​
    @Override
    public Policy save(Policy policy) {
        return mongoTemplate.save(policy, "policy");
    }
​
    @Override
    public long countByType(String bigTitle) {
        Query query = new Query(Criteria.where(BIG_TITLE).is(bigTitle));
        return mongoTemplate.count(query, Policy.class);
    }
​
    @Override
    public UpdateResult update(String childTitle, String content) {
        Query query = new Query(Criteria.where(CHILD_TITLE).is(childTitle));
        Update title = new Update().set("content", content).set("creatTime", DateUtil.format(LocalDateTime.now(), "yyyy年MM月dd日"));
        return mongoTemplate.updateFirst(query, title, Policy.class);
    }
​
    @Override
    public List<Policy> findLike(String childTitle) {
        Pattern pattern = Pattern.compile("^.*" + childTitle.trim() + ".*$", Pattern.CASE_INSENSITIVE);
        Query query = new Query(Criteria.where(CHILD_TITLE).regex(pattern));
        return  mongoTemplate.find(query,Policy.class);
    }
​
    @Override
    public DeleteResult delete(Integer id) {
        return mongoTemplate.remove(new Query(Criteria.where("_id").is(id)), Policy.class);
    }
​
    @Override
    public List<Policy> findAdmin(PolicyParam data) {
        Assert.notNull(data, "null");
        Criteria criteria = new Criteria();
        Query query = new Query(criteria);
        query.with(Sort.by(Sort.Direction.ASC, "_id"));
        query.skip(data.getCurrent() - 1).limit(data.getSize());
        return mongoTemplate.find(query, Policy.class);
    }
}

如果需要进行复杂点的条件查询操作,可以通过Criteria这个类去操作,具体场景可以自行研究。

  • Criteria类:封装所有的语句,以方法的形式查询。

  • Query类:将语句进行封装或者添加排序之类的操作。

        Criteria criteria = new Criteria();
   criteria.andOperator(Criteria.where("laguage").regex(data.getFlsName()),Criteria.where("name").regex(data.getName()));
        Query query = new Query(criteria);

简单测试一下:

 完全ok。需要注意的是:和Mysql数据库操作不同的是,mongoDB对于数据的规范敏感性不是很强,因此插入数据时需要注意实体类与集合字段名的对应问题,如果集合上的字段是create_time,但是实体类上是createTime,再插入数据时就会出现下面的情况:

 因为没有向Mysql那么强的字段映射约束(Mysql如果不一样并且没做格式化的话基本上会出现字段不一致导致插入失败),MongoDB并不会出现错误,它会产生新的字段并插入集合中,所以在MongoDB的使用上是需要注意这点的!

MongoRepository

熟悉Spring Data的同学应该对Repository比较熟悉。MongoRepository 继承于 PagingAndSortingRepository,而PagingAndSortingRepository则是继承于CrudRepository,这两个接口是所有Repository接口的父接口。所以MongoRepository 和前面 JPA、 Elasticsearch 的使用比较类似,都是 Spring Data 家族的产品,最终使用方法也就和 JPA、 ElasticSearch 的使用方式类似。

创建接口继承MongoRepository

package com.yy.service;
​
import com.yy.entity.Policy;
import org.springframework.data.mongodb.repository.MongoRepository;
​
/**
 * @author young
 * Date 2023/4/16 18:06
 * Description: final_design
 */
public interface MongoRepositoryTest extends MongoRepository<Policy,Long> {
}

其中T为仓库保存的bean类,TD为该bean的唯一标识的类型。之后在service中注入该接口就可以使用,无需实现里面的方法,spring会根据定义的规则自动生成。这样很多业务就可以像JPA那样省略了,直接拿来测试即可。

测试

 可以看到,非常方便,对于一些查询,分页操作,在使用MongoRepository的过程中,非模糊查询多配合使用Example/ExampleMatcher来完成工作,有兴趣的可以深入了解一下。如果MongoRepository能实现,尽量不要做冗余的工作,如果非要自定义方法才能实现,一定要符合Spring-Data的规则来定义方法名。定义方法名的规则:findBy+属性名(首字母大写)+其他参数(参数类型 参数名),具体参考JPA文档内的命名规则,笔者用的也不多。

但是它并不算特别灵活,因此有些地方两者结合使用是很不错的。

更多学习资源可在MongoDB中文网和菜鸟教程学习哦~

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

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

相关文章

大学刚毕业,用10000小时,走进字节跳动拿了offer

前言&#xff1a; 没有绝对的天才&#xff0c;只有持续不断的付出。对于我们每一个平凡人来说&#xff0c;改变命运只能依靠努力幸运&#xff0c;但如果你不够幸运&#xff0c;那就只能拉高努力的占比。 2020年7月&#xff0c;我有幸成为了字节跳动的一名测试开发&#xff0c…

IO流、多线程

FileInputStream FileOutputStream 原理&#xff1a; //1、创建一个FileOutputStream对象&#xff0c;构造方法中写入数据的目的地 FileOutStream fos new FileOutputStream("C:\\a.txt"); //2、调用FileOutputStream对象中的方法write&#xff0c;把数据写入文件中…

【微信小程序】关于实现自定义图片代替checkbox样式的记录

前言 checkbox很好使&#xff0c;使用中往往需要改变它的样式。 记录一下用自定义的图片代替原有样式的过程。 关于把checkbox从&#xff1a;变成的过程 正文 思路 问题拆分&#xff1a; ①如何修改checkbox的样式 ②如何使用图片代替原有样式 如何修改checkbox的样式 修…

氢原子的电子轨道半径、能量、速度

在https://blog.csdn.net/qq_35379989/article/details/130065868?spm1001.2014.3001.5501中我们已经给出了波尔模型的三大假设&#xff1a;定态假设、跃迁假设以及角动量量子化。 一、氢原子的轨道半径 在跃迁假设中&#xff0c;通过设定波尔模型轨道能量&#xff1a;与电子…

各种商业版本的ChatGPT已经推出了,还有必要搞个人的Chat吗?

一、引言 虽然市面上已经存在许多商业版本的ChatGPT交互产品&#xff0c;但在我们的开发中&#xff0c;决定专注于打造一个更加个性化、更贴合个人需求的智能助手。我们相信&#xff0c;每个人都是独一无二的&#xff0c;他们的需求也是各不相同的。因此&#xff0c;个人ChatG…

浅析PHP代码审计中的SQL注入漏洞

浅析PHP代码审计中的SQL注入漏洞1.概述2.普通注入3.编码注入宽字节注入二次urldecode注入4.漏洞防范gpc/rutime魔术引号过滤函数和类addslashes函数mysql_[real_]escape_string函数intval等字符转换PDO prepare预编译1.概述 SQL注入的攻击方式有下面几种&#xff1a; 在权限较…

常用电阻的作用

1、限流&#xff1a; 根据公式&#xff1a;I U / R&#xff1b;可知&#xff0c;电压固定的情况下&#xff0c;电阻越大&#xff0c;电流越小 常用于保护器件&#xff0c; 例如&#xff1a;MCU的输入输出信号线串联电阻&#xff0c;以避免电流过大&#xff0c;损坏元器件 …

快鲸scrm助力眼科机构提效客户运营,提升转化率

眼科机构普遍面临着以下几方面的业务挑战 &#xff08;1&#xff09;存在信任危机&#xff0c;用户决策周期长 眼睛是心灵的窗户&#xff0c;患者在对眼部治疗机构的选择上格外慎重&#xff0c;因而决策周期较长&#xff0c;眼科机构需要通过品牌建设、 IP 的打造、优质的产品…

SDL(2)-加载图片

加载BMP 1.使用SDL_init初始化SDL库 2.使用SDL_CreateWindow创建一个窗口 3.使用SDL_GetWindowSurface获取创建窗口的surface 4.使用SDL_LoadBMP加载一张BMP图片 5.使用SDL_BlitSurface将加载的bmp surface拷贝到窗口的surface 6.使用SDL_UpdateWindowSurface更新到窗口 …

【严重】vm2 <3.9.15 沙箱逃逸漏洞(CVE-2023-29017)

漏洞描述 vm2 是一个沙箱&#xff0c;用于在 Node.js 环境中运行不受信任的代码。宿主对象(Host objects)是指由 Node.js 的宿主环境提供的对象&#xff0c;例如全局对象、文件系统或网络请求等。 vm2 3.9.15之前版本中&#xff0c;当处理异步错误时未正确处理 Error.prepare…

中国大学哪家强?Python爬取排名榜,太棒啦(31)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 欢迎和猫妹一起&#xff0c;趣味学Python。 今日主题 如何用Python&#xff0c;抓取并分析2023中国大学排名数据。 用到的Python库有requests、bs4。 requests库 reque…

PixiJS 渲染优化

最近做在线CAD可视化与编辑&#xff0c;对前端的可视化渲染技术进行了选型&#xff0c;对于二维CAD来说一般用canvas就够了&#xff0c;但是canvas每一次平移&#xff0c;缩放&#xff0c;更新数据都需要重新计算渲染所有的图形数据&#xff0c;数据一多就显得非常卡。如果使用…

TCP和UDP在实际工作中的应用

前言 日常在网上浏览一些文章时都会看到一些介绍TCP和UDP的文章&#xff0c;每次都是草草浏览&#xff0c;而没有深入的去研究&#xff0c;这几天在做日志采集工具的时候恰好遇到一个问题&#xff0c;就是采集端将采集到的内容发送到服务端时这里采用的通信协议应该如何考量&a…

SpringBoot源码分析

SpringBoot源码分析1.启动类分析2.SpringBoot的项目启动流程1.SpringApplication构造函数1&#xff09;deduceFromClasspath()2&#xff09;getSpringFactoriesInstances2.1&#xff09;loadFactoryNames加载类名称2.2&#xff09;createSpringFactoriesInstances创建实例2.run…

gradle环境搭建

目录 gradle是什么 gradle环境搭建 IDEA 配置 Gradle 创建 Gradle 项目 gradle是什么 Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置&#xff0c;也增加了基于Kotlin语言的kotlin-based …

Java基础总结(二)

文章目录一、ObjectObject中的成员方法&#xff08;11个&#xff09;toStringequalsclone二、Objects三、BigInteger和BigDecimaBigIntegerBigDecima四、正则表达式五、DateJDK7前时间相关类SimpleDateFormat类Calendar类JDK8新增时间相关类六、包装类一、Object 没有一个属性…

【密码算法 之十四】非对称算法,ECC椭圆曲线算法 之 ECDSA、ECDH、SM2、SM9等

文章目录1. ECC椭圆曲线1.1 曲线类型1.2 曲线标准1.3 表示方法1.4 曲线运算1.4.1 点加&#xff08;Point Addition&#xff09;1.4.2 点乘&#xff08;Point Multiplication&#xff09;1.4.3 倍点&#xff08;Point Double&#xff09;2. ECDSA2.1 私钥签名2.2 公钥验签3. ECD…

Java——旋转数组的最小数字

题目链接 牛客在线oj题——旋转数组的最小数字 题目描述 有一个长度为 n 的非降序数组&#xff0c;比如[1,2,3,4,5]&#xff0c;将它进行旋转&#xff0c;即把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;变成一个旋转数组&#xff0c;比如变成了[3,4,5,1,2]&…

Stable Diffusion成为生产力工具(五):放大并修复老照片、马赛克照片、身份证件照

S&#xff1a;你安装stable diffusion就是为了看小姐姐么&#xff1f; I &#xff1a;当然不是&#xff0c;当然是为了公司的发展谋出路~~ 预先学习&#xff1a; 安装webui《Windows安装Stable Diffusion WebUI及问题解决记录》。运行使用时问题《Windows使用Stable Diffusion时…

Kubernetes 多集群管理工具Kuboard v3

目录 一、概述 二、安装和基本使用 2.1 添加k8s集群 2.2 信息查看 2.2.1概要信息查看 2.2.2导入集群的节点信息 2.2.3 存储 2.3创建工作负载 一、概述 Kuboard&#xff0c;是一款免费的 Kubernetes 图形化管理工具&#xff0c;Kuboard 力图帮助用户快速在 Kubernetes 上…