Java与AWS S3的文件操作
从零开始:Java与AWS S3的文件操作
- 一、什么是 AWS S3?
- AWS S3 的特点
- AWS S3 的应用场景
- 二、Java整合S3方法
- 使用 MinIO 客户端操作 S3
- 使用 AWS SDK 操作 S3 (推荐使用)
- 三、总结
一、什么是 AWS S3?
Amazon Simple Storage Service(简称 Amazon S3)是由亚马逊网络服务(AWS)提供的一种对象存储服务。它提供了一个高度可扩展、持久、安全且低成本的存储解决方案,用于存储和检索任意数量的数据。
AWS S3 的特点
- 高可用性和持久性:
-
AWS S3 的设计目标是为存储的数据提供 99.999999999%(11个9)的持久性,并确保 99.99% 的可用性。
-
数据会自动在多个地理位置冗余存储,以保证数据的高持久性和可用性。
- 安全性:
- AWS S3 提供了多种安全措施,包括传输中和存储时的数据加密、细粒度的访问控制策略、以及与 AWS Identity and Access Management (IAM) 集成的用户认证机制。
- 可扩展性:
-
AWS S3 可以自动扩展以处理从几字节到数十亿字节的数据。
-
用户无需预先配置存储容量,且可以根据需要动态增加或减少存储容量。
- 成本效益:
-
AWS S3 提供按需付费的计费模式,根据实际使用量收费,没有预付费用或最低消费。
-
用户可以选择不同的存储类别(如标准存储、智能分层存储、归档存储等),以优化存储成本。
- 简单易用:
-
AWS S3 提供了简单的 REST 和 SOAP API,开发人员可以方便地进行集成和操作。
-
AWS S3 管理控制台提供了直观的用户界面,用于管理存储桶和对象。
- 灵活的数据管理:
- 支持版本控制、生命周期管理、事件通知和跨区域复制等高级功能,帮助用户更好地管理数据。
- 高效的上传和下载速度:
-
AWS S3 提供了高效的数据传输速度,支持大规模数据的快速上传和下载。
-
上传速度:在良好的网络条件下,单个文件的上传速度可以达到数百兆比特每秒 (Mbps)。
-
下载速度:下载速度也可以达到数百兆比特每秒 (Mbps),尤其是在使用 Amazon CloudFront 进行内容分发时。
-
S3 Transfer Acceleration:通过启用 S3 Transfer Acceleration,可以进一步提升上传速度,全球范围内的传输速度可以提高 50-500% 以上,具体提升取决于用户的地理位置和网络条件。
AWS S3 的应用场景
- 静态网站托管:
- AWS S3 可以用于托管静态网站,包括 HTML、CSS、JavaScript 文件等。
- 备份和恢复:
- 作为企业级备份解决方案,AWS S3 可以用于存储备份数据,支持高持久性和快速恢复。
- 大数据分析:
-
数据湖:AWS S3 可以作为数据湖,用于存储和分析大规模的结构化和非结构化数据。
-
与 AWS 分析服务(如 Amazon Redshift、Amazon Athena)集成,进行大数据分析。
- 媒体存储和分发:
- AWS S3 可以存储大量的媒体文件(如图片、视频、音频),并通过 Content Delivery Network (CDN) 进行全球分发。
- 日志存储:
- 服务器和应用程序的日志可以存储在 AWS S3 中,以便于后续的分析和监控。
- 软件分发:
- 企业可以使用 AWS S3 进行软件包和应用程序更新的分发。
- 容灾和跨区域复制:
- 利用跨区域复制功能,企业可以在多个地理位置间复制数据,提高容灾能力。
二、Java整合S3方法
在 Java 中,可以通过两种主要方法与 S3 服务器进行交互:使用 MinIO 客户端和使用 AWS SDK。两者都能与 S3 服务兼容,但它们在使用方式和配置上有所不同。
使用 MinIO 客户端操作 S3
MinIO 是一个兼容 S3 API 的开源对象存储解决方案。它提供了与 AWS S3 相同的接口,因此可以使用 MinIO 的 SDK 来操作 S3 存储服务。MinIO 客户端非常适合在本地部署的 S3 兼容存储(如 MinIO 自身)和 AWS S3 上进行文件操作。
优点:
-
轻量级、开源,适合本地部署或私有云环境。
-
与 AWS S3 完全兼容,支持所有 S3 操作(如上传、下载、删除文件等)。
- 添加依赖
<!-- S3存储服务依赖 minio --><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.5</version></dependency>
- 配置AWS S3相关的信息
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;/*** @CreateTime: 2024/05/31 18:17* @Description: S3配置文件* @Version: 1.0*/
@Component
public class S3Config {@Value("${spring.s3_config.bucket_name}")private String bucketName;@Value("${spring.s3_config.endpoint}")private String s3Endpoint;@Value("${spring.s3_config.aws_access_key_id}")private String awsAccessKeyId;@Value("${spring.s3_config.aws_secret_access_key}")private String awsSecretAccessKey;private MinioClient minioClient;@PostConstructpublic void init() {// 初始化 MinioClient,minioClient = MinioClient.builder().endpoint(s3Endpoint)// s3服务器端点地址.credentials(awsAccessKeyId, awsSecretAccessKey)// 设置 访问凭证.build();}/*** 获取桶名*/public String getBucketName() {return bucketName;}/*** 获取minio客户端*/public MinioClient getMinioClient() {return minioClient;}
}
- 生成 S3 预览链接
/*** @description: 生成 S3 预览链接* @param realPath 生成 S3 预览链接的真实地址* @return 如果成功生成预览链接则返回链接字符串,否则返回 null*/public static String generatePreviewUrl(String realPath) {try {// 创建额外的请求参数,这里设置响应内容类型Map<String, String> reqParams = new HashMap<>();String contentType = FileEnum.getByExtension(realPath.substring(realPath.lastIndexOf(".") + 1)).getContentType();reqParams.put("response-content-type", contentType);// 使用 MinIO 客户端生成预签名的对象 URLreturn minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET) // 指定请求方法为 GET.bucket(bucketName) // 指定存储桶名称.object(realPath) // 指定对象名称.extraQueryParams(reqParams) // 添加额外的查询参数(这里是响应内容类型).expiry(7, TimeUnit.DAYS) // 指定预签名 URL 的有效期.build());} catch (Exception e) {// 捕获并打印任何异常log.error("生成预览链接失败: " + e);throw new RuntimeException("生成预览链接失败");}}
- 上传文件到S3
/*** @description: 上传文件到S3* @param file 上传的文件* @return 如果成功上传返回 true,否则返回 false*/public static String uploadFile(MultipartFile file) {try {// 获取上传的文件String fileName = file.getOriginalFilename();// 参数验证:确保文件名不为空if (fileName == null || fileName.isEmpty()) {throw new ServiceException("文件名无效");}String path = projectPath + fileName;// 使用 MinIO 客户端将文件上传到 S3 存储桶try (InputStream fileStream = file.getInputStream()) {minioClient.putObject(PutObjectArgs.builder().bucket(bucketName) // 指定存储桶名称.object(path) // 指定对象名称.stream(fileStream, file.getSize(), -1) // 输入流和大小.build());}return path;} catch (Exception e) {// 捕获并打印 MinIO 异常信息log.error("上传文件失败: " + e);throw new RuntimeException("上传文件失败");}}
- 删除 S3 文件
/*** @description: 删除 S3 文件* @param fileUrl 要删除的文件的 URL 或对象名称*/public static void removeFile(String realPath) {try {// 使用 MinIO 客户端删除对象minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName) // 指定存储桶名称.object(realPath) // 指定要删除的对象名称或 URL.build());} catch (Exception e) {log.error("文件删除失败: " + e);throw new RuntimeException("文件删除失败");}}
- 从s3获取文件流
当在大批量并发获取大文件流时,minio的方式可能会出现获取缓慢、卡死或中断的情况,推荐采用第二种方法AWS SDK的方式去获取文件流
/*** @description: 通过realPath获取文件流* @param: realPath* @return: InputStream **/public static InputStream downloadByS3Url(String realPath) throws IOException {try {// 获取文件流InputStream fis= minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(realPath).build());return fis;} catch (Exception e) {log.error("获取文件流失败: " + e);throw new RuntimeException("获取文件流失败");}}
- 从s3下载文件
/*** 下载文件* @param filePath MinIO 中的文件路径* @param downloadPath 本地下载路径*/public static void downloadFile(String filePath, String downloadPath) {try {// 使用 getObject 获取文件InputStream fileStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName) // 指定存储桶名称.object(filePath) // 指定文件路径.build());// 将文件内容写入到本地文件Path path = Paths.get(downloadPath);Files.copy(fileStream, path);System.out.println("文件已成功下载到: " + downloadPath);} catch (MinioException e) {log.error("下载文件失败: " + e);throw new RuntimeException("MinIO 下载文件失败");} catch (IOException e) {log.error("保存文件到本地时失败: " + e);throw new RuntimeException("保存文件到本地时失败");}}
使用 AWS SDK 操作 S3 (推荐使用)
AWS SDK 是 Amazon 提供的官方库,用于与 AWS 服务(包括 S3)进行交互。它不仅支持 AWS S3,还能支持其他 AWS 服务(如 EC2、DynamoDB 等)。如果你使用的是 AWS S3 或希望利用 AWS 的其它功能,AWS SDK 是推荐的选择。
优点:
-
官方支持,功能全面,适用于使用 AWS 云服务的场景。
-
可以访问 AWS 特有的功能和工具。
- 添加依赖
<!-- S3存储服务依赖 AWS SDK --><dependency><groupId>software.amazon.awssdk</groupId><artifactId>s3</artifactId><version>2.17.85</version></dependency>
- 配置AWS S3相关的信息
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;import javax.annotation.PostConstruct;
import java.net.URI;
import java.time.Duration;/*** @CreateTime: 2024/05/31 18:17* @Description: S3配置文件* @Version: 1.0*/
@Component
public class S3Config {@Value("${spring.s3_config.bucket_name}")private String bucketName;@Value("${spring.s3_config.endpoint}")private String s3Endpoint;@Value("${spring.s3_config.aws_access_key_id}")private String awsAccessKeyId;@Value("${spring.s3_config.aws_secret_access_key}")private String awsSecretAccessKey;private S3Client s3Client;@PostConstructpublic void init() {// 将凭证作为类级别的静态变量,避免每次调用都创建AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(awsAccessKeyId, awsSecretAccessKey);s3Client = S3Client.builder().region(Region.US_EAST_1) // 选择正确的区域.endpointOverride(URI.create(s3Endpoint))// s3 服务器端点地址.credentialsProvider(StaticCredentialsProvider.create(awsCredentials)).overrideConfiguration(ClientOverrideConfiguration.builder().apiCallTimeout(Duration.ofMinutes(10)) // 设置整个请求的最大超时为 10 分钟.apiCallAttemptTimeout(Duration.ofMinutes(9)) // 每次尝试的最大超时为 9 分钟.build()).build();}/*** 获取桶名*/public String getBucketName() {return bucketName;}/*** 获取亚马逊s3客户端*/public S3Client getS3Client() {return s3Client;}
}
- 生成 S3 预览链接
/*** @description: 生成 S3 预览链接* @param realPath 生成 S3 预览链接的真实地址* @return 如果成功生成预览链接则返回链接字符串,否则返回 null*/public static String generatePreviewUrl(String realPath) {try {// 创建 S3Presigner 实例private static final S3Presigner presigner = S3Presigner.builder().region(Region.US_EAST_1) // 选择正确的区域.credentialsProvider(StaticCredentialsProvider.create(awsCredentials)).build();// 获取文件扩展名并根据扩展名获取内容类型String extension = realPath.substring(realPath.lastIndexOf(".") + 1);String contentType = FileEnum.getByExtension(extension).getContentType();// 构建 GetObjectRequest 对象GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(bucketName).key(realPath).responseContentType(contentType) // 设置响应内容类型.build();// 构建 GetObjectPresignRequest 对象GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder().signatureDuration(Duration.ofDays(7)) // 设置预签名 URL 的有效期.getObjectRequest(getObjectRequest).build();// 生成预签名的 URLreturn presigner.presignGetObject(getObjectPresignRequest).url().toString();} catch (Exception e) {// 捕获并打印任何异常log.error("生成预览链接失败: " + e);throw new RuntimeException("生成预览链接失败");}}
- 上传文件到S3
/*** @description: 上传文件到S3* @param file 上传的文件* @return 如果成功上传返回 true,否则返回 false*/public static String uploadFile(MultipartFile file) {try {// 获取上传的文件String fileName = file.getOriginalFilename();// 参数验证:确保文件名不为空if (fileName == null || fileName.isEmpty()) {throw new ServiceException("文件名无效");}String path = projectPath + fileName; // 在S3存储桶中存储的路径// 获取文件输入流try (InputStream fileStream = file.getInputStream()) {// 创建 PutObjectRequestPutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(bucketName).key(path) // 设置 S3 存储对象的路径.build();// 上传文件到 S3PutObjectResponse putObjectResponse = s3Client.putObject(putObjectRequest,RequestBody.fromInputStream(fileStream, file.getSize()));// 返回上传文件的路径return path;} catch (Exception e) {log.error("上传文件失败: " + e);throw new RuntimeException("上传文件失败");}}
- 删除 S3 文件
/*** @description: 删除 S3 文件* @param fileUrl 要删除的文件的 URL 或对象名称*/public static void removeFile(String realPath) {try {// 创建删除文件的请求对象DeleteObjectRequest deleteObjectRequest = DeleteObjectRequest.builder().bucket(bucketName) // 存储桶名称.key(realPath) // 文件路径.build();// 执行文件删除操作s3Client.deleteObject(deleteObjectRequest);} catch (Exception e) {log.error("文件删除失败: " + e);throw new RuntimeException("文件删除失败");}}
- 从s3获取文件流
/*** @description: 通过realPath获取文件流* @param: realPath* @return: InputStream **/public static InputStream downloadByS3Url(String realPath) throws IOException {try {// 创建 GetObjectRequest 请求,指定存储桶名称和对象键GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(bucketName) // S3 存储桶名称.key(realPath) // S3 对象键.build();// 获取对象并返回文件的输入流InputStream fis = s3Client.getObject(getObjectRequest); // 获取文件输入流return fis;} catch (Exception e) {log.error("获取文件流失败: " + e);throw new RuntimeException("获取文件流失败");}}
- 从s3下载文件
/*** @description: 从 S3 下载文件* @param filePath 要下载的文件路径* @param downloadPath 本地存储路径*/public static void downloadFile(String filePath, String downloadPath) {try {// 创建 GetObjectRequest 请求GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(bucketName) // 存储桶名称.key(filePath) // S3 中的文件路径.build();// 执行下载操作并获取文件响应GetObjectResponse getObjectResponse = s3Client.getObject(getObjectRequest,Paths.get(downloadPath)); // 下载到指定路径// 处理下载后的响应,如果需要可以做进一步处理System.out.println("文件已下载: " + getObjectResponse);} catch (S3Exception e) {// 捕获 AWS S3 异常并记录错误log.error("文件下载失败: " + e.awsErrorDetails().errorMessage());throw new RuntimeException("文件下载失败");} catch (Exception e) {// 捕获其他异常log.error("文件下载失败: " + e);throw new RuntimeException("文件下载失败");}}
三、总结
MinIO 客户端:
- 适用于本地部署的 S3 兼容存储,或者想要避免依赖 AWS 提供的 SDK。通过 MinIO,你可以在 S3 和 MinIO 之间无缝迁移,或用于私有云环境。
AWS SDK:
- 适用于直接操作 AWS S3 服务,提供更多 AWS 的特性和功能支持。如果你的应用已经在 AWS 云上运行,使用 AWS SDK 是更理想的选择。
相关文章:
Java与AWS S3的文件操作
从零开始:Java与AWS S3的文件操作 一、什么是 AWS S3?AWS S3 的特点AWS S3 的应用场景 二、Java整合S3方法使用 MinIO 客户端操作 S3使用 AWS SDK 操作 S3 (推荐使用) 三、总结 一、什么是 AWS S3? Amazon Simple Sto…...
详解 YOLOv5 模型运行参数含义以及设置及在 PyCharm 中的配置方法
详解 YOLOv5 模型运行参数含义以及设置及在 PyCharm 中的配置方法 这段代码中使用的命令行参数允许用户在运行 YOLOv5 模型时自定义多种行为和设置。以下是各个参数的详细说明和使用示例,以及如何在 PyCharm 中设置这些参数以确保正确运行带有参数的脚本。 命令行…...
Vue根据Div内容的高度给其Div设置style height
在 Vue.js 中,你可以使用 JavaScript 来动态地根据 div 的内容高度来设置其 style 的 height 属性。这通常是在组件挂载或更新时完成的,因为这时你已经有了实际的 DOM 元素可以操作。 以下是一个简单的例子,展示了如何实现这一点:…...

驱动篇的开端
准备 在做之后的动作前,因为win7及其以上的版本默认是不支持DbgPrint(大家暂时理解为内核版的printf)的打印,所以,为了方便我们的调试,我们先要修改一下注册表 创建一个reg文件然后运行 Windows Registr…...

OpenSSL 自建CA 以及颁发证书(网站部署https双向认证)
前言 1、前面写过一篇 阿里云免费ssl证书申请与部署,大家可以去看下 一、openssl 安装说明 1、这部分就不再说了,我使用centos7.9,是自带 openssl的,window的话,要去下载安装 二、CA机构 CA机构,全称为…...

吾杯网络安全技能大赛WP(部分)
吾杯网络安全技能大赛WP(部分) MISC Sign 直接16进制解码即可 原神启动 将图片用StegSolve打开 找到了压缩包密码 将解出docx文件改为zip 找到了一张图片和zip 再把图片放到stegSlove里找到了img压缩包的密码 然后在document.xml里找到了text.zip压缩包密码 然后就出来fl…...
按vue组件实例类型实现非侵入式国际化多语言翻译
#vue3##国际化##本地化##international# web界面国际化,I18N(Internationalization,国际化),I11L(International,英特纳雄耐尔),L10N(Localization,本地化)&…...
Java入门:22.集合的特点,List,Set和Map集合的使用
1 什么是集合 本质就是容器的封装,可以存储多个元素 数组一旦创建,长度就不能再改变了。 数组一旦创建,存储内容的类型不能改变。 数组可以存储基本类型,也可以存储引用类型。 数组可以通过length获得容量的大小,但…...

重生之我在异世界学编程之C语言:深入指针篇(下)
大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 目录 题集(1)指针笔试题1&a…...

理解Parquet文件和Arrow格式:从Hugging Face数据集的角度出发
parquet发音:美 [pɑrˈkeɪ] 镶木地板;拼花木地板 理解Parquet文件和Arrow格式:从Hugging Face数据集的角度出发 引言 在机器学习和大数据处理中,数据的存储和传输格式对于性能至关重要。两种广泛使用的格式是 Parquet 和 Arr…...
下载 M3U8 格式的视频
要下载 M3U8 格式的视频(通常是 HLS 视频流),可以尝试以下几种方法: 方法 1:使用下载工具(推荐) 1. IDM(Internet Download Manager): 安装 IDM 并启用浏…...

Tomcat使用教程
下载地址:https://tomcat.apache.org/ 配置环境变量 变量名: CATALINA_HOME 变量值: D:\tools\apache-tomcat-9.0.97 Path: %CATALINA_HOME%\bin 启动Tomcat(打开命令提示符) startup.bat 解决乱码问题(打开conf\logging.properties) java.util.logging.Conso…...

LabVIEW氢气纯化控制系统
基于LabVIEW的氢气纯化控制系统满足氢气纯化过程中对精确控制的需求,具备参数设置、过程监控、数据记录和报警功能,体现了LabVIEW在复杂工业控制系统中的应用效能。 项目背景 在众多行业中,尤其是石油化工和航天航空领域,氢气作为…...

现在的电商风口已经很明显了
随着电商行业的不断发展,直播带货的热潮似乎正逐渐降温,而货架电商正成为新的焦点。抖音等平台越来越重视货架电商,强调搜索功能的重要性,预示着未来的电商中心将转向货架和搜索。 在这一转型期,AI技术与电商的结合为…...
Uniapp触底刷新
在你的代码中,使用了 scroll-view 来实现一个可滚动的评论区域,并且通过监听 scrolltolower 事件来触发 handleScrollToLower 函数,以实现“触底更新”或加载更多评论的功能。 关键部分分析: scroll-view 组件: scroll-view 是一…...

开源项目 - face parsing 人脸区域分割 人像区域分割 人脸分割 人像区域分割 BiSeNet
开源项目 - face parsing 人脸区域分割 人像区域分割 人脸分割 人像区域分割 BiSeNet 项目地址:GitHub - XIAN-HHappy/face_parsing: face_parsing 脸部分割 示例: 助力快速掌握数据集的信息和使用方式。 数据可以如此美好!...

python游戏设计---飞机大战
1.前言 上次做飞机大战游戏有人这么说: 好好好!今天必须整一个,今天我们来详细讲解一下,底部找素材文件下载!!! 2.游戏制作 目录如下: 1.导入的包 import pygame import sys imp…...

13TB的StarRocks大数据库迁移过程
公司有一套StarRocks的大数据库在大股东的腾讯云环境中,通过腾讯云的对等连接打通,通过dolphinscheduler调度datax离线抽取数据和SQL计算汇总,还有在大股东的特有的Flink集群环境,该环境开发了flink开发程序包部署,实时…...

HTTP代理有那些常见的安全协议?
在数据采集领域,HTTP代理扮演着至关重要的角色,它不仅帮助我们访问互联网资源,还涉及到数据的安全传输。了解HTTP代理中常见的安全协议对于保护数据安全、提高数据采集效率至关重要。那么,有哪些安全协议是在HTTP代理中常用的呢&a…...

Kylin Server V10 下基于Kraft模式搭建Kafka集群
一、Kraft 模式与 ZooKeeper 模式简介 在Kafka 2.8 之前,Kafka 重度依赖 ZooKeeper 集群做元数据管理、Controller 的选举等(统称为共识服务);当ZooKeeper 集群性能发生抖动时,Kafka 的性能也会受到很大的影响。如下图所示: 在 Kafka 2.8 之后,引入了基于 Raft …...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...