MinIO 教程:从入门到Spring Boot集成

文章目录

  • 一. MinIO 简介
    • 1. 什么是MinIO?
    • 2. 应用场景
  • 二. 文件系统存储发展史
    • 1. 服务器磁盘(本地存储)
    • 2. 分布式文件系统(如 HDFS、Ceph、GlusterFS)
    • 3. 对象存储(如 MinIO、AWS S3)
    • 4.对比总结
    • 5.选型建议
    • 6.示例方案
  • 三.MinIO基础概念
    • MinIO的基础概念
    • MinIO 纠删码 EC (Erasure Code)
  • 三. MinIO 安装指南
    • 1 单机部署
    • 2 分布式集群部署
    • 3 Docker 部署
  • 四. MinIO 基础使用
    • 1. 基础命令
      • 1.1 安装与配置
    • 2. 存储桶管理
      • 2.1 创建存储桶
      • 2.2 删除存储桶
      • 2.3 列出存储桶
      • 2.4 查看存储桶策略
      • 2.5 设置存储桶策略
    • 3. 对象管理
      • 3.1 上传文件
      • 3.2 下载文件
      • 3.3 列出对象
      • 3.4 删除对象
      • 3.5 批量删除对象
    • 4. 高级功能
      • 4.1 同步数据
      • 4.2 数据迁移
      • 4.3 设置生命周期规则
      • 4.4 查看服务器信息
      • 4.5 用户管理
      • 4.6 策略管理
    • 5. 常用快捷命令
  • 五. Spring Boot 集成 MinIO
    • 1 添加依赖
    • 2.在SpringBoot的配置文件中编写 MinIO 的配置:
    • 3.编写 MinIO 配置类
    • 4.编写 MinIO 的工具类
    • 5.业务测试
  • 六. 常见问题

一. MinIO 简介

1. 什么是MinIO?

MinlO是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据。例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。

MinlO是一个非常轻量的服务 可以很简单的和其他应用的结合,类似NodeJS, Redis或者MySQL。

MInIO官网

  • 核心特性
    • 支持海量非结构化数据(图片、视频、日志等)支持单个对象最大5TB。
    • 轻量级(二进制文件仅数十MB)。
    • 支持单机部署和分布式集群。
    • 提供数据加密、版本控制、生命周期管理等企业级功能。

2. 应用场景

  • 云原生存储(Kubernetes 集成)。
  • 大数据存储(与 Hadoop、Spark 对接)。
  • 多媒体资源存储与加速。

二. 文件系统存储发展史

1. 服务器磁盘(本地存储)

定义

  • 直接挂载在服务器上的物理或虚拟磁盘(如 SSD、HDD),通过文件系统(如 ext4、NTFS)管理数据。

优点

  • 低延迟:数据直接读写,无需网络开销。
  • 高性能:适合频繁读写、小文件操作(如数据库事务)。
  • 简单易用:无需复杂配置,开箱即用。

缺点

  • 单点故障:硬盘损坏可能导致数据丢失。
  • 扩展性差:受限于单机容量,无法横向扩展。
  • 资源共享困难:数据无法跨服务器直接访问。

适用场景

  • 单机应用(如小型网站、个人博客)。
  • 高性能需求场景(如实时数据库、缓存服务)。
  • 临时文件存储(如日志、临时缓存)。

2. 分布式文件系统(如 HDFS、Ceph、GlusterFS)

定义

  • 通过网络将多台服务器的存储资源整合为统一命名空间,提供文件存储和共享能力(如 HDFS、Ceph、GlusterFS)。
  • 它使文件可以跨越多个服务器或存储设备存储和访问。DFS 通过网络将多个存储资源组合成一个统一的文件系统,使用户和应用程序可以像访问本地文件一样透明地访问远程文件。

优点

  • 横向扩展:可动态添加节点,支持 PB 级存储。
  • 高可用性:数据多副本或纠删码冗余,容忍节点故障。
  • 共享访问:多客户端可同时读写同一文件系统。

缺点

  • 复杂度高:需管理元数据、数据分布和一致性。
  • 性能瓶颈:元数据操作(如 HDFS 的 NameNode)可能成为瓶颈。
  • 成本较高:需维护多节点集群,硬件和运维成本上升。

适用场景

  • 大数据处理(如 Hadoop 生态、日志分析)。
  • 需要共享存储的场景(如 Kubernetes 动态卷、虚拟机镜像存储)。
  • 高吞吐需求(如视频流媒体、科学计算)。

3. 对象存储(如 MinIO、AWS S3)

定义

  • 以对象(Object)为基本单元的存储系统,每个对象包含数据、元数据和唯一标识符(如 S3 的 Key),通过 RESTful API 访问。

优点

  • 海量扩展:支持百亿级对象存储,自动管理数据分布。
  • 高可用与持久性:数据跨多节点冗余(如 MinIO 的纠删码)。
  • 云原生集成:兼容 S3 API,无缝对接云服务和工具链。
  • 成本效益:按需付费,支持冷热数据分层存储。

缺点

  • 高延迟:基于 HTTP 协议,不适合实时读写。
  • 弱一致性:部分系统存在最终一致性(如 S3 的跨区域复制)。
  • 文件系统语义缺失:不支持随机写入、追加操作。

适用场景

  • 非结构化数据存储(如图片、视频、文档)。
  • 云原生应用(如 Kubernetes 静态资源托管)。
  • 大数据与 AI 数据湖(如 Spark 读取 Parquet 文件)。
  • 备份与归档(如日志存储、合规性归档)。

4.对比总结

特性服务器磁盘分布式文件系统对象存储
数据模型层级文件系统层级文件系统平坦对象(Bucket/Object)
扩展性有限(单机)横向扩展(多节点)海量扩展(自动管理)
访问协议本地文件系统 APINFS/CIFS 或专用协议RESTful API(S3 兼容)
延迟极低中等(受网络影响)较高(HTTP 开销)
适用数据结构化、小文件大文件、流式数据非结构化、海量数据
维护成本高(需管理集群)中等(云服务免运维)

5.选型建议

  1. 优先选择对象存储

    • 云原生应用或需要弹性扩展的场景。
    • 存储海量非结构化数据(如用户上传文件)。
    • 需要跨地域数据同步或版本控制。
  2. 选择分布式文件系统

    • 大数据处理(如 HDFS 与 MapReduce 结合)。
    • 需要共享文件系统语义(如多个 VM 挂载同一目录)。
  3. 保留本地存储

    • 对延迟敏感的应用(如实时数据库)。
    • 小规模或临时性存储需求。

6.示例方案

  • 混合方案

    • 使用本地存储处理热数据(如 Redis 缓存),对象存储存放冷数据(如历史日志)。
    • 分布式文件系统(如 Ceph)作为底层存储,提供块存储、文件存储和对象存储统一接口。
  • 云原生方案

    • Kubernetes 中使用 MinIO 作为持久化存储后端,结合 S3 API 实现无状态应用的数据持久化。

通过合理选择存储方案,可显著提升系统性能、降低成本并保障数据可靠性。

特性传统分布式文件系统MinIO
数据模型层级目录结构平坦命名空间(Bucket/Object)
接口专用协议(如 NFS)S3 兼容 REST API
扩展性需手动配置自动数据分布与负载均衡
适用场景通用存储云原生、大数据、AI 数据湖

三.MinIO基础概念

MinIO的基础概念

● Object: 存储到Minio的基本对象,如文件、字节流,Anything…

● Bucket:用来存储Object的逻辑空间。每个Bucket之间的数据是相互隔离的。对于客户端而言,就相当于一个存放文件的顶层文件夹。

● Drive: 即存储数据的磁盘,在MinIO启动时,以参数的方式传入。Minio 中所有的对象数据都会存储在Drive里。

● Set:即一组Drive的集合,分布式部署根据集群规模自动划分一 个或多个Set, 每个Set中的Drive分布在不同位置。一个对象存储在一个Set 上。(For example: {1…44} is divided into 4 sets each of size 16.)

● 一个对象存储在一 个Set上● 一个集群划分为多个Set● 一个Set包含的Drive数显是固定的,默认由系统根据集群规模自动计算得出● 一个SET中的Drive尽可能分布在不同的节点上

MinIO 纠删码 EC (Erasure Code)

纠删码(Erasure Code, EC) 是一种数据保护方法,它将数据分割成片段,生成冗余数据块,并将这些数据块存储在不同的位置,如磁盘、存储节点或其他地理位置。MinIO 采用 Reed-Solomon 纠删码实现,将对象拆分成数据块和奇偶校验块,以提高数据的冗余性和可用性。

简单来说就是可以通过数学计算,把丢失的数据进行还原,它可以将n份原始数据,增加m份数据,并能通过n+m份中的任意n份数据,还原为原始数据。
即如果有任意小于等于m份的数据失效,仍然能通过剩下的数据还原出来。

举个最简单例子就是有两个数据(d1, d2),用一个校验和y(d1 + d2 = y)即可保证即使丢失其中一个,依然可以还原数据。如丢失 d1 ,则使用 y - d2 = d1 还原,同理,d2 丢失或者y丢失,均可通过计算得出。

三. MinIO 安装指南

1 单机部署

# 下载并运行(Linux/macOS)
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
./minio server /data --console-address :9001
  • 访问管理界面:http://localhost:9001

2 分布式集群部署

# 启动4节点集群(假设4台服务器IP为192.168.1.101-104)
minio server http://192.168.1.10{1...4}/data
  • 自动数据冗余:采用纠删码(Erasure Code)保障数据可靠性。

3 Docker 部署

docker run -p 9000:9000 -p 9001:9001 \-v /data:/data \-e "MINIO_ROOT_USER=admin" \-e "MINIO_ROOT_PASSWORD=password" \minio/minio server /data --console-address :9001

四. MinIO 基础使用

1. 基础命令

1.1 安装与配置

  • 安装 mc

    wget https://dl.min.io/client/mc/release/linux-amd64/mc
    chmod +x mc
    sudo mv mc /usr/local/bin/
    
  • 设置别名(连接 MinIO 服务):

    mc alias set <ALIAS> <ENDPOINT> <ACCESS_KEY> <SECRET_KEY>
    
    • 示例:

      mc alias set myminio http://localhost:9000 admin password
      
  • 查看别名列表

    mc alias list
    

2. 存储桶管理

2.1 创建存储桶

mc mb <ALIAS>/<BUCKET_NAME>
  • 示例:

    mc mb myminio/mybucket
    

2.2 删除存储桶

mc rb <ALIAS>/<BUCKET_NAME>
  • 示例:

    mc rb myminio/mybucket
    

2.3 列出存储桶

mc ls <ALIAS>
  • 示例:

    mc ls myminio
    

2.4 查看存储桶策略

mc policy get <ALIAS>/<BUCKET_NAME>
  • 示例:

    mc policy get myminio/mybucket
    

2.5 设置存储桶策略

mc policy set <POLICY> <ALIAS>/<BUCKET_NAME>
  • 策略选项:none(私有)、download(只读)、upload(上传)、public(公开)。

  • 示例:

    mc policy set public myminio/mybucket
    

3. 对象管理

3.1 上传文件

mc cp <SOURCE_FILE> <ALIAS>/<BUCKET_NAME>/<TARGET_PATH>
  • 示例:

    mc cp myfile.txt myminio/mybucket/
    

3.2 下载文件

mc cp <ALIAS>/<BUCKET_NAME>/<OBJECT_PATH> <DESTINATION>
  • 示例:

    mc cp myminio/mybucket/myfile.txt ./downloaded_file.txt
    

3.3 列出对象

mc ls <ALIAS>/<BUCKET_NAME>
  • 示例:

    mc ls myminio/mybucket
    

3.4 删除对象

mc rm <ALIAS>/<BUCKET_NAME>/<OBJECT_PATH>
  • 示例:

    mc rm myminio/mybucket/myfile.txt
    

3.5 批量删除对象

mc rm --recursive --force <ALIAS>/<BUCKET_NAME>/<PREFIX>
  • 示例:

    mc rm --recursive --force myminio/mybucket/old_data/
    

4. 高级功能

4.1 同步数据

  • 本地到远程同步

    mc mirror <LOCAL_DIR> <ALIAS>/<BUCKET_NAME>
    
    • 示例:

      mc mirror ./local_data/ myminio/mybucket/
      
  • 远程到本地同步

    mc mirror <ALIAS>/<BUCKET_NAME> <LOCAL_DIR>
    

4.2 数据迁移

  • 从其他 S3 兼容存储迁移到 MinIO

    mc mirror s3-source/ myminio/mybucket/
    

4.3 设置生命周期规则

mc ilm add <ALIAS>/<BUCKET_NAME> --expiry-days <DAYS>
  • 示例:

    mc ilm add myminio/mybucket --expiry-days 30
    

4.4 查看服务器信息

mc admin info <ALIAS>
  • 示例:

    mc admin info myminio
    

4.5 用户管理

  • 添加用户

    mc admin user add <ALIAS> <ACCESS_KEY> <SECRET_KEY>
    
    • 示例:

      mc admin user add myminio newuser newpassword
      
  • 删除用户

    mc admin user remove <ALIAS> <ACCESS_KEY>
    

4.6 策略管理

  • 创建策略

    mc admin policy create <ALIAS> <POLICY_NAME> <POLICY_FILE>
    
    • 示例:

      mc admin policy create myminio readonly-policy policy.json
      
  • 绑定策略到用户

    mc admin policy attach <ALIAS> <POLICY_NAME> --user=<USER>
    

5. 常用快捷命令

功能命令
查看帮助mc --help
查看某个命令的帮助mc <COMMAND> --help
检查配置是否正确mc alias test <ALIAS>
清空存储桶mc rb --force <ALIAS>/<BUCKET_NAME>
查看存储桶占用空间mc du <ALIAS>/<BUCKET_NAME>

五. Spring Boot 集成 MinIO

1 添加依赖

<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.2</version>
</dependency>

2.在SpringBoot的配置文件中编写 MinIO 的配置:

minio:url: http://127.0.0.1:9005 #ip地址accessKey: admin #  账号secretKey: admin962464 #  密码secure: false #如果是true,则用的是https而不是http,默认值是truebucketName: "test"  # 桶的名字 相当于文件夹

3.编写 MinIO 配置类

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {/*** 服务地址*/private String url;/*** 用户名*/private String accessKey;/*** 密码*/private String secretKey;/*** 存储桶名称*/private String bucketName;@Beanpublic MinioClient getMinioClient() {return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();}
}

4.编写 MinIO 的工具类

import com.jjy.shopping_file_service.config.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;@Slf4j
@Component
public class MinIOUtil {@Resourceprivate MinioConfig minioConfig;@Resourceprivate MinioClient minioClient;/*** 查看存储bucket是否存在** @param bucketName 存储桶名称* @return boolean*/public Boolean bucketExists(String bucketName) {Boolean found;try {found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return found;}/*** 创建存储bucket** @param bucketName 存储桶名称* @return Boolean*/public Boolean makeBucket(String bucketName) {try {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** 删除存储bucket** @param bucketName 存储桶名称* @return Boolean*/public Boolean removeBucket(String bucketName) {try {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** 获取全部bucket** @return 存储桶列表*/public List<Bucket> getAllBuckets() {try {return minioClient.listBuckets();} catch (Exception e) {e.printStackTrace();}return null;}/*** 文件上传** @param file 文件* @return 文件对象名称*/public String upload(MultipartFile file) {String originalFilename = file.getOriginalFilename();System.out.println(originalFilename);if (!StringUtils.hasText(originalFilename)) {throw new RuntimeException();}String fileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));String prefix = new SimpleDateFormat("yyyy/MM/dd").format(new Date());String objectName = prefix + "/" + fileName;try {PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(minioConfig.getBucketName()).object(objectName).stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();// 文件名称相同会覆盖minioClient.putObject(objectArgs);} catch (Exception e) {e.printStackTrace();return null;}return objectName;}/*** 预览图片** @param fileName 文件名称* @return 文件预览链接*/public String preview(String fileName) {// 查看文件地址GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder().bucket(minioConfig.getBucketName()).object(fileName).method(Method.GET).build();try {String url = minioClient.getPresignedObjectUrl(build);return url;} catch (Exception e) {e.printStackTrace();}return null;}/*** 文件下载** @param fileName 文件名称* @param res      response*/public void download(String fileName, HttpServletResponse res) {GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName).build();try (GetObjectResponse response = minioClient.getObject(objectArgs)) {byte[] buf = new byte[1024];int len;try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {while ((len = response.read(buf)) != -1) {os.write(buf, 0, len);}os.flush();byte[] bytes = os.toByteArray();res.setCharacterEncoding("utf-8");res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);try (ServletOutputStream stream = res.getOutputStream()) {stream.write(bytes);stream.flush();}}} catch (Exception e) {e.printStackTrace();}}/*** 查看文件对象** @return 存储bucket内文件对象信息*/public List<Item> listObjects() {Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(minioConfig.getBucketName()).build());List<Item> items = new ArrayList<>();try {for (Result<Item> result : results) {items.add(result.get());}} catch (Exception e) {e.printStackTrace();return null;}return items;}/*** 删除** @param fileName 文件名称* @return 是否删除成功*/public boolean remove(String fileName) {try {minioClient.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName).build());} catch (Exception e) {return false;}return true;}}

5.业务测试

import com.cyw.miniodemo.config.MinioConfig;
import com.cyw.miniodemo.pojo.Rst;
import com.cyw.miniodemo.service.FileUploadService;
import com.cyw.miniodemo.utils.MinIOUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;@Slf4j
@RestController
@RequestMapping("/api/file")
@AllArgsConstructor
public class FileUploadController {private MinioConfig minioConfig;private MinIOUtil minIOUtil;private FileUploadService fileUploadService;@GetMapping("/bucketExists")public Rst bucketExists(@RequestParam("bucketName") String bucketName) {Map<String, Object> map = new HashMap<>();map.put("bucketExists", minIOUtil.bucketExists(bucketName));return Rst.ok("查询成功", map);}@GetMapping("/makeBucket")public Rst makeBucket(@RequestParam("bucketName") String bucketName) {Map<String, Object> map = new HashMap<>();map.put("makeBucketSuccess", minIOUtil.makeBucket(bucketName));return Rst.ok("创建成功", map);}@GetMapping("/removeBucket")public Rst removeBucket(@RequestParam("bucketName") String bucketName) {Map<String, Object> map = new HashMap<>();map.put("deleteBucketSuccess", minIOUtil.removeBucket(bucketName));return Rst.ok("删除成功", map);}@GetMapping("/getAllBuckets")public Rst getAllBuckets() {Map<String, Object> map = new HashMap<>();map.put("buckets", minIOUtil.getAllBuckets());return Rst.ok("查询成功", map);}@PostMapping("/upload")public Rst upload(@RequestParam("file") MultipartFile file) {String objectName = minIOUtil.upload(file);if (objectName != null) {Map<String, Object> map = new HashMap<>();map.put("url", (minioConfig.getEndpoint() + "/" + minioConfig.getBucketName() + "/" + objectName));return Rst.ok("上传成功", map);}return Rst.fail("上传失败");}@GetMapping("/preview")public Rst preview(@RequestParam("fileName") String fileName) {Map<String, Object> map = new HashMap<>();map.put("url", minIOUtil.preview(fileName));return Rst.ok("预览成功", map);}@GetMapping("/download")public Rst download(@RequestParam("fileName") String fileName, HttpServletResponse resp) {minIOUtil.download(fileName, resp);return Rst.ok();}@PostMapping("/delete")public Rst remove(@RequestBody Map<String, String> params) {String url = params.get("url");String objName = url.substring(url.lastIndexOf(minioConfig.getBucketName() + "/") + minioConfig.getBucketName().length() + 1);log.info("删除对象: {}", objName);minIOUtil.remove(objName);return Rst.ok("删除成功");}
}

六. 常见问题

  • 如何扩容集群?:直接添加新节点,MinIO 自动数据再平衡。
  • 数据安全性:启用 HTTPS、配置 Bucket Policy、使用 Server-Side Encryption。
  • 性能优化:调整纠删码配置(如 MINIO_STORAGE_CLASS_STANDARD=EC:4)。

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

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

相关文章

电竞俱乐部护航点单小程序,和平地铁俱乐部点单系统,三角洲护航小程序,暗区突围俱乐部小程序

电竞俱乐部护航点单小程序开发&#xff0c;和平地铁俱乐部点单系统&#xff0c;三角洲护航小程序&#xff0c;暗区突围俱乐部小程序开发 端口包含&#xff1a; 超管后台&#xff0c; 老板端&#xff0c;打手端&#xff0c;商家端&#xff0c;客服端&#xff0c;管事端&#x…

基于 IPMI + Kickstart + Jenkins 的 OS 自动化安装

Author&#xff1a;Arsen Date&#xff1a;2025/04/26 目录 环境要求实现步骤自定义 ISO安装 ipmitool安装 NFS定义 ks.cfg安装 HTTP编写 Pipeline 功能验证 环境要求 目标服务器支持 IPMI / Redfish 远程管理&#xff08;如 DELL iDRAC、HPE iLO、华为 iBMC&#xff09;&…

如何在SpringBoot中通过@Value注入Map和List并使用YAML配置?

在SpringBoot开发中&#xff0c;我们经常需要从配置文件中读取各种参数。对于简单的字符串或数值&#xff0c;直接使用Value注解就可以了。但当我们需要注入更复杂的数据结构&#xff0c;比如Map或者List时&#xff0c;该怎么操作呢&#xff1f;特别是使用YAML这种更人性化的配…

短信验证码安全实战:三网API+多语言适配开发指南

在短信服务中&#xff0c;创建自定义签名是发送通知、验证信息和其他类型消息的重要步骤。万维易源提供的“三网短信验证码”API为开发者和企业提供了高效、便捷的自定义签名创建服务&#xff0c;可以通过简单的接口调用提交签名给运营商审核。本文将详细介绍如何使用该API&…

RabbitMQ和Seata冲突吗?Seata与Spring中的事务管理冲突吗

1. GlobalTransactional 和 Transactional 是否冲突&#xff1f; 答&#xff1a;不冲突&#xff0c;它们可以协同工作&#xff0c;但作用域不同。 Transactional: 这是 Spring 提供的注解&#xff0c;用于管理单个数据源内的本地事务。在你当前的 register 方法中&#xff0c…

一台服务器已经有个python3.11版本了,如何手动安装 Python 3.10,两个版本共存

环境&#xff1a; debian12.8 python3.11 python3.10 问题描述&#xff1a; 一台服务器已经有个python3.11版本了&#xff0c;如何手动安装 Python 3.10&#xff0c;两个版本共存 解决方案&#xff1a; 1.下载 Python 3.10 源码&#xff1a; wget https://www.python.or…

c++中的enum变量 和 constexpr说明符

author: hjjdebug date: 2025年 04月 23日 星期三 13:40:21 CST description: c中的enum变量 和 constexpr说明符 文章目录 1.Q:enum 类型变量可以有,--操作吗&#xff1f;1.1补充: c/c中enum的另一个细微差别. 2.Q: constexpr 修饰的函数,要求传入的参数必需是常量吗&#xff…

postman工具

postman工具 进入postman官网 www.postman.com/downloads/ https://www.postman.com/downloads/ https://www.postman.com/postman/published-postman-templates/documentation/ae2ja6x/postman-echo?ctxdocumentation Postman Echo is a service you can use to test your …

Spring和Spring Boot集成MyBatis的完整对比示例,包含从项目创建到测试的全流程代码

以下是Spring和Spring Boot集成MyBatis的完整对比示例&#xff0c;包含从项目创建到测试的全流程代码&#xff1a; 一、Spring集成MyBatis示例 1. 项目结构 spring-mybatis-demo/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com.example/…

【数据可视化-24】巧克力销售数据的多维度可视化分析

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个…

c语言-分支结构

以下是我初学C语言的笔记记录&#xff0c;欢迎留言补充 一&#xff0c;分支结构分为几个 两个&#xff0c;一个是if语句&#xff0c;一个是Switch语句 二&#xff0c;if语句 &#xff08;1&#xff09;结构体 int main() {if()//判断条件{//表达式}else if()//判断条件{//表达式…

数据库MySQL学习——day4(更多查询操作与更新数据)

文章目录 1、聚合函数&#xff08;Aggregate Functions&#xff09;2、分组查询&#xff08;GROUP BY&#xff09;3、更新数据&#xff08;UPDATE&#xff09;4、删除数据&#xff08;DELETE&#xff09;5、进阶练习示例6、 今日小结 1、聚合函数&#xff08;Aggregate Functio…

Spark-SQL 项目

一、项目概述 &#xff08;一&#xff09;实验目标 统计有效数据条数&#xff1a;筛选出uid、phone、addr三个字段均无空值的记录并计数。提取用户数量最多的前 20 个地址&#xff1a;按地址分组统计用户数&#xff0c;按降序排序后取前 20 名。 &#xff08;二&#xff09;…

Redis的ZSet对象底层原理——跳表

我们来聊聊「跳表&#xff08;Skip List&#xff09;」&#xff0c;这是一个既经典又优雅的数据结构&#xff0c;尤其在 Redis 中非常重要&#xff0c;比如 ZSet&#xff08;有序集合&#xff09;底层就用到了跳表。 &#x1f31f; 跳表&#xff08;Skip List&#xff09;简介 …

2025深圳中兴通讯安卓开发社招面经

2月27号 中兴通讯一面 30多分钟 自我介绍 聊项目 我的优缺点&#xff0c;跟同事相比&#xff0c;有什么突出的地方 Handler机制&#xff0c;如何判断是哪个消息比较耗时 设计模式&#xff1a;模板模式 线程的状态 线程的开启方式 线程池原理 活动的启动模式 Service和Activity…

【Castle-X机器人】二、智能导览模块安装与调试

持续更新。。。。。。。。。。。。。。。 【Castle-X机器人】智能导览模块安装与调试 二、智能导览模块安装与调试2.1 智能导览模块安装2.2 智能导览模块调试2.2.1 红外测温传感器测试2.2.2 2D摄像头测试 二、智能导览模块安装与调试 2.1 智能导览模块安装 使用相应工具将智能…

深入理解二叉树遍历:递归与栈的双重视角

二叉树的遍历前序遍历中序遍历后续遍历总结 二叉树的遍历 虽然用递归的方法遍历二叉树实现起来更简单&#xff0c;但是要想深入理解二叉树的遍历&#xff0c;我们还必须要掌握用栈遍历二叉树&#xff0c;递归其实就是利用了系统栈去遍历。特此记录一下如何用双重视角去看待二叉…

Qt Creator中自定义应用程序的可执行文件图标

要在Qt Creator中为你的应用程序设置自定义可执行文件图标&#xff0c;你需要按照以下步骤操作&#xff1a; Windows平台设置方法 准备图标文件&#xff1a; 创建一个.ico格式的图标文件&#xff08;推荐使用256x256像素&#xff0c;包含多种尺寸&#xff09; 可以使用在线工…

Windows11系统中GIT下载

Windows11系统中GIT下载 0、GIT背景介绍0.0 GIT概述0.1 GIT诞生背景0.2 Linus Torvalds 的设计目标0.3 Git 的诞生&#xff08;2005 年&#xff09;0.4 Git 的后续发展0.5 为什么 Git 能成功&#xff1f; 1、资源下载地址1.1 官网资源1.2 站内资源 2、安装指导3、验证是否下载完…

react的fiber 用法

在 React 里&#xff0c;Fiber 是 React 16.x 及后续版本采用的协调算法&#xff0c;它把渲染工作分割成多个小任务&#xff0c;让 React 可以在渲染过程中暂停、恢复和复用任务&#xff0c;以此提升渲染性能与响应能力。在实际开发中&#xff0c;你无需直接操作 Fiber 节点&am…