当前位置: 首页 > news >正文

spring boot 2.7整合Elasticsearch Java client + ingest attachment实现文档解析

一、软件环境

软件版本号备注
Spring boot2.7.23.x版本建议使用ElasticSearch8.x
ElasticSearch7.17.4ElasticSearch 7.x 可使用JDK 8
ElasticSearch 8.x 要求使用JDK 11+

二、安装ElasticSearch

下载地址:https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.4-linux-x86_64.tar.gz

上传压缩包至/usr/local/

cd /usr/local/
//解压
tar -xvf elasticsearch-7.17.4-linux-x86_64.tar.gz

修改配置文件/usr/local/elasticsearch-7.17.4/config/elasticsearch.yml

注意 :后面需要跟一个空格

//数据存储路径,文件不存在则先创建
path.data: /usr/local/elasticsearch-7.17.4/data
//日志存储路径
path.logs: /usr/local/elasticsearch-7.17.4/logs
//在底部增加以下内容,以便支持设置密码
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

修改内存参数配置/usr/local/elasticsearch-7.17.4/config/jvm.options,可根据实际需求配置。

-Xms512m
-Xmx512m

JDK版本兼容,该版本默认要求JDK11,系统配置了JDK8,启动时会冲突,故进行以下调整

编辑/usr/local/elasticsearch-7.17.4/bin/elasticsearch-env,注释红框部分

ElasticSearch不能以root启动,为指定用户配置权限

//ElasticSearch不能以root启动,为指定用户配置权限
chown -R 用户名:用户名 /usr/local/elasticsearch-7.17.4
//启动ElasticSearch,需切换为非root用户
/usr/local/elasticsearch-7.17.4/bin/elasticsearch -d
//配置密码,需先启动一次ElasticSearch
/usr/local/elasticsearch-7.17.4/bin/elasticsearch-setup-passwords interactive

三、安装Kibana

下载地址:https://artifacts.elastic.co/downloads/kibana/kibana-7.17.4-linux-x86_64.tar.gz

上传压缩包至/usr/local/

cd /usr/local/
//解压
tar -zxvf kibana-7.17.4-linux-x86_64.tar.gz

编辑配置文件/usr/local/kibana-7.17.4-linux-x86_64/config/kibana.yml

//端口号
server.port: 5601//服务器绑定地址,允许所有网络接口访问
server.host: "0.0.0.0"//elasticsearch账户配置
elasticsearch.username: "kibana_system"
elasticsearch.password: "密码"//中文
i18n.locale: "zh-CN"

kibana和ElasticSearch一样,不能以root启动,为指定用户配置权限

//kibana不能以root启动,为指定用户配置权限
chown -R 用户名:用户名 /usr/local/kibana-7.17.4-linux-x86_64//前台启动
/usr/local/kibana-7.17.4-linux-x86_64/bin/kibana
//后台启动
nohup /usr/local/kibana-7.17.4-linux-x86_64/bin/kibana &

四、IK中文分词器

下载地址(根据对应的ElasticSearch版本号进行下载):

https://github.com/infinilabs/analysis-ik/releases

在ElasticSearch安装路径的plugins文件夹里,创建ik文件夹,如/usr/local/elasticsearch-7.17.4/plugins/ik,解压文件放到该路径下。

重启ElasticSearch即可。

五、Spring boot整合ElasticSearch

在Es7.15版本之后,es官方将它的高级客户端RestHighLevelClient标记为弃用状态。同时推出了全新的java API客户端Elasticsearch Java API Client,该客户端也将在Elasticsearch8.0及以后版本中成为官方推荐使用的客户端。

本文直接使用Elasticsearch Java API Client,后续方便升级8.x

pom.xml中增加:

<dependency><groupId>co.elastic.clients</groupId><artifactId>elasticsearch-java</artifactId><version>7.17.24</version>
</dependency>

配置文件:

spring.elasticsearch.uris=http://localhost:9200
spring.elasticsearch.username=elastic
spring.elasticsearch.password=*******

配置类ElasticsearchConfig:

@Configuration
public class ElasticsearchConfig {@Value("${spring.elasticsearch.uris}")private String uris;@Value("${spring.elasticsearch.username}")private String username;@Value("${spring.elasticsearch.password}")private String password;@Beanpublic ElasticsearchClient elasticsearchClient() {BasicCredentialsProvider credsProv = new BasicCredentialsProvider();credsProv.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));RestClient restClient = RestClient.builder(HttpHost.create(uris)).setHttpClientConfigCallback(hc -> hc.setDefaultCredentialsProvider(credsProv)).build();#多节点可参考/*RestClient restClient = RestClient.builder(new HttpHost("192.168.1.10", 9200),new HttpHost("192.168.1.11", 9200),new HttpHost("192.168.1.12", 9200)).build();*/ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());return new ElasticsearchClient(transport);}
}

在service类中自动装配ElasticsearchClient,后续直接使用

@Autowired
private ElasticsearchClient esClient;

六、索引相关操作

1.索引是否存在

http请求

GET /索引名称

JAVA  API

BooleanResponse existsResponse = esClient.indices().exists(builder -> builder.index("索引名称"));
if (existsResponse.value()) {//存在
}else{//不存在
}

2.创建索引

http请求

PUT /索引名称
{//指定默认分词器为ik_max_word"settings" : {"index" : {"analysis.analyzer.default.type": "ik_max_word"}},"mappings": {"properties": {"字段1": {"type": "keyword"    //keyword不进行分词},"字段2": {"type": "text"       //text进行分词},"字段3": {"type":   "date","format": "yyyy-MM-dd HH:mm:ss"}}}
}

JAVA  API

//方式一
//定义映射
TypeMapping typeMapping = new TypeMapping.Builder().properties("integer字段", p -> p.integer(i -> i)).properties("keyword字段",p->p.keyword(k -> k)).properties("text字段", p -> p.text(t -> t)).properties("日期字段", p -> p.date(d -> d.format("yyyy-MM-dd"))).properties("日期时间字段", p -> p.date(d -> d.format("yyyy-MM-dd HH:mm:ss"))).build();
esClient.indices().create(new CreateIndexRequest.Builder().index("索引名称").mappings(typeMapping).build());//方式二、根据json内容创建索引
String mappings = """{"mappings" : {"properties" : {"integer字段" : {"type" : "integer"},"keyword字段" : {"type" : "keyword"},"text字段" : {"type" : "text"},"日期字段" : {"type" : "date","index" : false,"format" : "yyyy-MM-dd"},"日期时间字段" : {"type" : "date","index" : false,"format" : "yyyy-MM-dd HH:mm:ss"}}}}""";
esClient.indices().create(new CreateIndexRequest.Builder().index("索引名称").withJson(new StringReader(mappings)).build());

3.查询索引映射信息

http请求

GET /索引名称/_mapping

JAVA  API

GetMappingResponse response = esClient.indices().getMapping(builder -> builder.index("索引名称"));
IndexMappingRecord indexMappingRecord = response.get("索引名称");
TypeMapping typeMapping = indexMappingRecord.mappings();
Map<String, Property> properties=typeMapping.properties();
List<IndexMapping> mappings=new ArrayList<>();
for(String key:properties.keySet()){IndexMapping mapping_item=new IndexMapping();//字段名称mapping_item.setField_name(key);String json_str=String.valueOf(properties.get(key)._get());json_str=json_str.substring(json_str.indexOf("Property: ")+9);JSONObject property_json= JSONObject.parseObject(json_str);//字段类型mapping_item.setField_type(property_json.getString("type"));//自定义格式if(property_json.containsKey("format")){mapping_item.setField_format(property_json.getString("format"));}mappings.add(mapping_item);
}

4.向索引添加映射字段

http请求

PUT /索引名称/_mapping
{"properties": {"新增字段": {"type": "keyword"}}
}

JAVA  API

//JSONObject mappings 为要增加的映射内容,参考http请求,这里省略细节
PutMappingResponse response=esClient.indices().putMapping(new PutMappingRequest.Builder().index("索引名称").withJson(new StringReader(mappings.toString())).build());
// 响应状态
Boolean acknowledged = response.acknowledged();

5.删除索引

http请求

DELETE /索引名称

JAVA  API

DeleteIndexResponse response = esClient.indices().delete(builder -> builder.index("索引名称");
// 响应状态
Boolean acknowledged = response.acknowledged();

七、文档相关操作

1.添加文档

http请求

POST /索引名称/_doc/文档id
{"字段1": "内容","字段2": "内容"
}

JAVA  API

// 插入文档到索引
//JSONObject json为文档内容
IndexRequest<Object> request = new IndexRequest.Builder<>().index("索引名称").id(”文档id“).document(json).build();
IndexResponse response = esClient.index(request);

2.编辑文档

http请求

PUT /索引名称/_doc/文档id
{"要修改的字段1":"要修改的内容","要修改的字段2":"要修改的内容"
}

JAVA  API

//要修改的内容用Map组装
Map<String,Object> updateMap=new HashMap<>();
UpdateRequest<Object, Object> updateRequest = new UpdateRequest.Builder<>().index("索引名称").id(”文档id“).doc(updateMap).build();UpdateResponse<Object> updateResponse = esClient.update(updateRequest, Object.class);

3.根据id查询文档

http请求

GET /索引名称/_doc/文档id

JAVA  API

GetRequest getRequest = new GetRequest.Builder().index("索引名称").id(”文档id“).build();
GetResponse<Object> response = esClient.get(getRequest, Object.class);
if (response.found()) {return response.source();
} else {throw new MyException(ResultEnum.DATA_IS_EXIST.getCode(),"数据不存在");
}

4.删除文档

http请求

DELETE /索引名称/_doc/文档id

JAVA  API

//支持批量删除,String[] id_arr为要删除的文档id数组
List<BulkOperation> bulkOperations = new ArrayList<>();
for(int i=0;i<id_arr.length;i++){String del_id=id_arr[i];bulkOperations.add(new BulkOperation.Builder().delete(d -> d.id(del_id).index("索引名称")).build());
}
BulkResponse bulkResponse = esClient.bulk(e -> e.index("索引名称").operations(bulkOperations));

5.筛选文档

http请求

GET blog/_search
{"query": {"bool" : {//必须满足的条件"must" : [//精确匹配{"term" : { "字段名称" : "自动内容" }},//模糊查询{"query_string": {"default_field": "字段名称","query": "*模糊匹配内容*"}}],//排除的条件"must_not" : [//精确匹配{"term" : { "字段名称" : "自动内容" }},//模糊查询{"query_string": {"default_field": "字段名称","query": "*模糊匹配内容*"}}]}},//排序规则"sort": [{//根据评分排序"_score": {"order": "desc"}},{"字段名称": {"order": "desc"}}],//从第几条开始获取,从0开始"from":  0,//获取多少条"size":  10
}

JAVA  API

//queryJson是查询条件的json,参考http方式
SearchRequest searchRequest = new SearchRequest.Builder().index("索引名称").withJson(new StringReader(queryJson.toString())).build();
SearchResponse<Object> response = esClient.search(searchRequest,Object.class);
List<Hit<Object>> hits = response.hits().hits();
//不需要输出文档id的话可以不要
List<Map<String,Object>> data_list = hits.stream().map(p->{Map<String,Object> map=new HashMap<>();map.put("docoment_id",p.id());map.putAll((Map<String, Object>)p.source());return map;}).collect(Collectors.toList());
//data_list是数据list,
//符合条件的数据总数为(int)response.hits().total().value()

八、结合ingest attachment实现文档解析

1.安装ingest attachment插件

下载地址(版本号可根据对应的ElasticSearch版本号进行替换):

https://artifacts.elastic.co/downloads/elasticsearch-plugins/ingest-attachment/ingest-attachment-7.17.4.zip

安装方法:

切换至ElasticSearch根目录,执行

#linux
./bin/elasticsearch-plugin install file:///path/to/ingest-attachment-7.17.4.zip
#windows
./bin/elasticsearch-plugin install file:///C:/path/to/ingest-attachment-7.17.4.zip

重启ElasticSearch,定义文本抽取管道

PUT /_ingest/pipeline/attachment
{"description": "Extract attachment information","processors": [{"attachment": {"field": "content","ignore_missing": true}},{"remove": {"field": "content"}}]
}

attachment中指定要过滤的字段为content,所以写入Elasticsearch时需要将文档内容放在content字段,传入内容需为文档的base64编码。支持txt、word、Excel、PPT、PDF等文件格式。

2.文件转base64编码

// 文件路径
String filePath = "E:/xxx/xxx.pdf"; // 请替换为你的文件路径
// 读取文件字节
byte[] fileBytes = Files.readAllBytes(Paths.get(filePath)); // 读取文件内容
String base64_str = Base64.getEncoder().encodeToString(fileBytes); // 编码为Base64字符串

3.实现文档解析

/*** 模拟管道处理,仅模拟,不会真正插入文档*/
Map<String, Object> source = new HashMap<>();
source.put("content", "文档的base64编码");
SimulateResponse response = client.ingest().simulate(builder -> builder.id("my-pipeline").docs(documentBuilder -> documentBuilder.index("索引名称").id(”文档id“).source(JsonData.of(source))));
log.info("response={}", response);

4.在文档索引的过程中使用

Map<String, Object> source = new HashMap<>();
source.put("content", "文档的base64编码");
IndexRequest<Object> request = new IndexRequest.Builder<>().index("索引名称").id(”文档id“).document(JsonData.of(source)).pipeline("attachment").build();IndexResponse response = esClient.index(request);logger.info(response.toString());

相关文章:

spring boot 2.7整合Elasticsearch Java client + ingest attachment实现文档解析

一、软件环境 软件版本号备注Spring boot2.7.23.x版本建议使用ElasticSearch8.xElasticSearch7.17.4ElasticSearch 7.x 可使用JDK 8 ElasticSearch 8.x 要求使用JDK 11 二、安装ElasticSearch 下载地址&#xff1a;https://artifacts.elastic.co/downloads/elasticsearch/el…...

一、PyCharm 基本快捷键总结

PyCharm 快捷键 前言一、编辑&#xff08;Editing&#xff09;二、查找/替换(Replace)三、运行(Running)四、重构(Refactoring)五、基本(General) 前言 下面我们将学习一些 Pycharm 中的快捷键来帮我们更好的使用工具。 一、编辑&#xff08;Editing&#xff09; 快捷键快捷键…...

Windows系统C盘爆满了,如何清理?

Windows系统C盘爆满了&#xff0c;如何清理&#xff1f; 大家好&#xff0c;我是秋意零。 相信使用过Windows系统的朋友&#xff0c;都见过C盘那道靓丽的 “红色风景线” &#xff01; 我自己的Win10系统&#xff0c;已经使用了4-5年时间了。最近频频出现"红色风景线&q…...

【C++】踏上C++学习之旅(一):初识C++和命名空间

文章目录 前言1. 初识C2. C的发展阶段2. 命名空间2.1 为什么要有命名空间&#xff1f;2.2 命名空间的语法2.3 命名空间的原理2.4 使用命名空间的三种方式2.4.1 加命名空间名称及作用域限定符( :: )2.4.2 使用using关键字将命名空间中某个成员 引入2.4.3 使用using namespace 命…...

tensorflow入门案例手写数字识别人工智能界的helloworld项目落地1

参考 https://tensorflow.google.cn/?hlzh-cn https://tensorflow.google.cn/tutorials/keras/classification?hlzh-cn 项目资源 https://download.csdn.net/download/AnalogElectronic/89872174 文章目录 一、案例学习1、导入测试和训练数据集&#xff0c;定义模型&#xff…...

深度学习——线性神经网络(三、线性回归的简洁实现)

目录 3.1 生成数据集3.2 读取数据集3.3 定义模型3.4 初始化模型参数3.5 定义损失函数3.6 定义优化算法3.7 训练 在上一节中&#xff0c;我们通过张量来自定义式地进行数据存储和线性代数运算&#xff0c;并通过自动微分来计算梯度。实际上&#xff0c;由于数据迭代器、损失函数…...

本地部署 Milvus

本地部署 Milvus 1. Install Milvus in Docker2. Install Attu, an open-source GUI tool 1. Install Milvus in Docker curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.shbash standalone_embed.sh …...

Git基础-配置http链接的免密登录

问题描述 当我们在使用 git pull 或者 git push 进行代码拉取或代码提交时&#xff0c; 若我们的远程代码仓库是 http协议的链接时&#xff0c;就是就会提示我们进行账号密码的登录。 每次都要登录&#xff0c;这未免有些麻烦。 本文介绍一下免密登录的配置。解决方案 1 执行…...

华为OD机试真题-编码能力提升-2024年OD统一考试(E卷)

最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客 每一题都含有详细的解题思路和代码注释,精编c++、JAVA、Python三种语言解法。帮助每一位考生轻松、高效刷题。订阅后永久可看,持续跟新。 题目描述 为了提升软件编码能力,小…...

高被引算法GOA优化VMD,结合Transformer-SVM的轴承诊断,保姆级教程!

本期采用2023年瞪羚优化算法优化VMD&#xff0c;并结合Transformer-SVM实现轴承诊断&#xff0c;算是一个小创新方法了。需要水论文的童鞋尽快&#xff01; 瞪羚优化算法之前推荐过&#xff0c;该成果于2023年发表在计算机领域三区SCI期刊“Neural Computing and Applications”…...

半小时速通RHCSA

1-7章: #01创建以上目录和文件结构&#xff0c;并将/yasuo目录拷贝4份到/目录下 #02查看系统合法shell #03查看系统发行版版本 #04查看系统内核版本 #05临时修改主机名 #06查看系统指令的查找路径 #07查看passwd指令的执行路径 #08为/yasuo/ssh_config文件在/mulu目录下创建软链…...

人工智能和机器学习之线性代数(一)

人工智能和机器学习之线性代数&#xff08;一&#xff09; 人工智能和机器学习之线性代数一将介绍向量和矩阵的基础知识以及开源的机器学习框架PyTorch。 文章目录 人工智能和机器学习之线性代数&#xff08;一&#xff09;基本定义标量&#xff08;Scalar&#xff09;向量&a…...

STM32外设应用详解

STM32外设应用详解 STM32微控制器是意法半导体&#xff08;STMicroelectronics&#xff09;推出的一系列基于ARM Cortex-M内核的高性能、低功耗32位微控制器。它们拥有丰富的外设接口和功能模块&#xff0c;可以满足各种嵌入式应用需求。本文将详细介绍STM32的外设及其应用&am…...

docker详解介绍+基础操作 (三)优化配置

1.docker 存储引擎 Overlay&#xff1a; 一种Union FS文件系统&#xff0c;Linux 内核3.18后支持 Overlay2&#xff1a;Overlay的升级版&#xff0c;docker的默认存储引擎&#xff0c;需要磁盘分区支持d-type功能&#xff0c;因此需要系统磁盘的额外支持。 关于 d-type 传送…...

细说Qt的状态机框架及其用法

文章目录 使用场景基本用法状态定义添加转换历史状态QStateMachine是Qt框架中用于构建状态机的一个类,它属于Qt的状态机框架(State Machine Framework)。这个框架提供了一种模型,用于设计响应不同事件(如用户输入、文件I/O或网络活动)的应用程序的行为。通过使用状态机,开发…...

Oracle-表空间与数据文件操作

目录 1、表空间创建 2、表空间修改 3、数据文件可用性切换操作 4、数据文件和表空间删除 1、表空间创建 &#xff08;1&#xff09;为 ORCL 数据库创建一个名为 BOOKTBS1 的永久表空间&#xff0c;数据文件为d:\bt01.dbf &#xff0c;大小为100M&#xff0c;区采用自动扩展…...

C# WinForm实现画笔签名及解决MemoryBmp格式问题

目录 需求 实现效果 开发运行环境 设计实现 界面布局 初始化 画笔绘图 清空画布 导出位图数据 小结 需求 我的文章 《C# 结合JavaScript实现手写板签名并上传到服务器》主要介绍了 web 版的需求实现&#xff0c;本文应项目需求介绍如何通过 C# WinForm 通过画布画笔…...

GC1272替代APX9172/茂达中可应用于电脑散热风扇应用分析

在电脑散热风扇应用中&#xff0c;选择合适的驱动器件对于风扇的性能和效率至关重要。以下是对GC1272替代APX9172/茂达在此类应用中的分析&#xff1a; 1. 功能比较 GC1272&#xff1a; 主要用于驱动直流风扇&#xff0c;具有高效的电流控制和调速功能。支持PWM调速&#xff0…...

《Linux从小白到高手》综合应用篇:详解Linux系统调优之服务器硬件优化

List item 本篇介绍Linux服务器硬件调优。硬件调优主要包括CPU、内存、磁盘、网络等关键硬件组。 1. CPU优化 选择适合的CPU&#xff1a; –根据应用需求选择多核、高频的CPU&#xff0c;以满足高并发和计算密集型任务的需求。CPU缓存优化&#xff1a; –确保CPU缓存&#x…...

PHP政务招商系统——高效连接共筑发展蓝图

政务招商系统——高效连接&#xff0c;共筑发展蓝图 &#x1f3db;️ 一、政务招商系统&#xff1a;开启智慧招商新篇章 在当今经济全球化的背景下&#xff0c;政务招商成为了推动地方经济发展的重要引擎。而政务招商系统的出现&#xff0c;更是为这一进程注入了新的活力。它…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...

GraphRAG优化新思路-开源的ROGRAG框架

目前的如微软开源的GraphRAG的工作流程都较为复杂&#xff0c;难以孤立地评估各个组件的贡献&#xff0c;传统的检索方法在处理复杂推理任务时可能不够有效&#xff0c;特别是在需要理解实体间关系或多跳知识的情况下。先说结论&#xff0c;看完后感觉这个框架性能上不会比Grap…...

32位寻址与64位寻址

32位寻址与64位寻址 32位寻址是什么&#xff1f; 32位寻址是指计算机的CPU、内存或总线系统使用32位二进制数来标识和访问内存中的存储单元&#xff08;地址&#xff09;&#xff0c;其核心含义与能力如下&#xff1a; 1. 核心定义 地址位宽&#xff1a;CPU或内存控制器用32位…...

python读取SQLite表个并生成pdf文件

代码用于创建含50列的SQLite数据库并插入500行随机浮点数据&#xff0c;随后读取数据&#xff0c;通过ReportLab生成横向PDF表格&#xff0c;包含格式化&#xff08;两位小数&#xff09;及表头、网格线等美观样式。 # 导入所需库 import sqlite3 # 用于操作…...

npm安装electron下载太慢,导致报错

npm安装electron下载太慢&#xff0c;导致报错 背景 想学习electron框架做个桌面应用&#xff0c;卡在了安装依赖&#xff08;无语了&#xff09;。。。一开始以为node版本或者npm版本太低问题&#xff0c;调整版本后还是报错。偶尔执行install命令后&#xff0c;可以开始下载…...

AT模式下的全局锁冲突如何解决?

一、全局锁冲突解决方案 1. 业务层重试机制&#xff08;推荐方案&#xff09; Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减&#xff08;自动加全…...