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

【C++】nlohmann::json 配置加载技术实践:从基础到高级应用

一、nlohmann::json 库概况与核心特性

nlohmann::json 是 C++ 社区最受欢迎的 JSON 库之一,其设计理念简洁即美,通过单头文件实现完整的 JSON 解析、序列化和操作功能。

1.1 基本特性

nlohmann::json是一个现代C++编写的开源JSON库,采用MIT协议发布。其核心特点包括:

  • 单头文件设计:只需包含json.hpp即可使用
  • 直观的API:提供STL风格的容器访问方式
  • 强类型支持:严格的类型检查和自动类型转换
  • 完备的RFC 7159支持
  • C++11及以上版本支持
#include <nlohmann/json.hpp>
using json = nlohmann::json;

1.2 优缺点分析

优点

  • 开发效率高:支持链式调用和直观的语法
  • 内存安全:自带异常处理机制
  • 兼容性好:支持自定义类型转换
  • 文档完善:提供详细的在线文档

缺点

  • 编译时延长:模板元编程导致头文件膨胀
  • 性能中等:对性能敏感场景不如rapidjson高效
  • 二进制体积:可能增加可执行文件大小

1.3 典型应用场景

  • 配置文件读写
  • RESTful API交互
  • 数据序列化/反序列化
  • 结构化日志记录
  • 跨语言数据交换
json
+json()
+json(initializer_list)
+parse(const string&)
+dump(int indent=4)
+operator[](const key&)
+get()
+is_array()
+is_object()
+size()
«Template»
basic_json
+value_type
+array_t
+object_t
+string_t
+serializer
+parser
json_pointer
+to_string()
+get(const json&)
+contains(const json&)
«Exception»
json_exception
+what()
json_serializer
json_parser

二、核心操作代码示例

2.1 创建与修改

// 创建空对象
json j;// 添加基础类型
j["int_val"] = 42;
j["pi"] = 3.1416;
j["name"] = "Alice";// 添加嵌套对象
j["address"]["city"] = "Hangzhou";
j["address"]["zip"] = "310000";// 添加数组
j["tags"] = {"AI", "C++", "JSON"};// 链式初始化
json config = {{"enable_ssl", true},{"base_url", "https://api.example.com"},{"models", {"gpt-4", "claude-3"}}
};// 动态修改
config["model_name"] = "gpt-4-turbo";  // 自动类型推导
config["api_key"] = "sk-xxxxxx";

2.2 文件读写与遍历

// 写入文件(缩进美化)
std::ofstream("config.json") << std::setw(4) << config;// 读取文件
std::ifstream fin("config.json");
json loaded_config = json::parse(fin);// 遍历键值对
for (auto& [key, value] : loaded_config.items()) {std::cout << key << ": " << value.type_name() << std::endl;
}// 对象遍历
for (auto& [key, value] : j.items()) {std::cout << key << ": " << value << '\n';
}// 数组遍历
for (auto& element : j["tags"]) {std::cout << element << '\n';
}

解析过程包含词法分析、语法分析和对象构建步骤:

调用 parse 函数
词法分析
语法分析
构建 JSON 对象
返回解析结果

2.3 数组与嵌套对象

// 添加端点配置
json endpoint = {{"path", "/v1/chat"}, {"timeout", 30}};
config["chat_endpoint"] = endpoint;// 操作数组
config["models"].push_back("mixtral-8x22b");  // 追加元素
if (!config["models"].empty()) {std::cout << "首模型: " << config["models"][0] << std::endl; // 输出 gpt-4
}

序列化与反序列化流程:

User JSON 调用 parse() 反序列化 返回 JSON 对象 调用 dump() 序列化 返回 JSON 字符串 User JSON

三、实现灵活配置加载的工程实践

3.1 模板函数封装

参考文中 PlatformConfig 的实现,我们可通过模板函数 Util::JsonGet 统一处理字段加载:

template<typename T>
static bool JsonGet(const nlohmann::json& jdat, const std::string& name, T& val)
{// 使用contains检查键存在性(避免异常)if (!jdat.contains(name)){return false;}try {val = jdat[name].get<T>();return true;}catch (...) {return false;}
}// 针对可选字段的重载版本
template<typename T>
void JsonGet(const json& j, const std::string& key, T& target, const T& default_val) {target = j.value(key, default_val);
}

3.2 分层配置加载

void PlatformConfig::from_json(const json& j) {Util::JsonGet(j, "enable_ssl", enable_ssl);Util::JsonGet(j, "base_url", base_url);// 处理嵌套对象if (j.contains("generate_endpoint")) {generate_endpoint.from_json(j["generate_endpoint"]);}// 带默认值的可选字段Util::JsonGet(j, "model_name", model_name, "gpt-4-default");
}

四、NLOHMANN_DEFINE_TYPE_INTRUSIVE 的高价技巧

4.1 宏定义的优势

对于简单结构体,可使用宏实现自动转换:

struct EndpointConfig {std::string path;int timeout;NLOHMANN_DEFINE_TYPE_INTRUSIVE(EndpointConfig, path, timeout)
};

该宏会生成:

  • to_jsonfrom_json函数
  • 要求所有字段必须存在且非空
  • 字段顺序需要严格匹配

4.2 注意事项

  1. 严格模式:遇到缺失字段会抛出json::out_of_range异常
  2. 类型安全:类型不匹配时抛出json::type_error
  3. 侵入式设计:需在类内部声明
  4. 字段顺序:必须与声明顺序一致

4.3 异常处理建议

try {config.from_json(j);
} catch (const json::exception& e) {std::cerr << "Config Error: " << e.what();
}

五、最佳实践总结

  1. 分层加载:基础字段用模板函数,复杂结构用自动转换
  2. 防御式编程:对可选字段使用contains()检查
  3. 版本兼容:使用try-catch处理新增/废弃字段
  4. 性能优化:对高频访问数据建立缓存
  5. 单元测试:验证各种边界case

相关文章:

【C++】nlohmann::json 配置加载技术实践:从基础到高级应用

一、nlohmann::json 库概况与核心特性 nlohmann::json 是 C 社区最受欢迎的 JSON 库之一&#xff0c;其设计理念简洁即美&#xff0c;通过单头文件实现完整的 JSON 解析、序列化和操作功能。 1.1 基本特性 nlohmann::json是一个现代C编写的开源JSON库&#xff0c;采用MIT协议…...

ngx_regex_init

定义在 src\core\ngx_regex.c void ngx_regex_init(void) { #if !(NGX_PCRE2)pcre_malloc ngx_regex_malloc;pcre_free ngx_regex_free; #endif } NGX_PCRE21 #if !(NGX_PCRE2) 就为假 条件不成立 ngx_regex_init 函数就成了空实现 NGX_PCRE2 被定义&#xff0c;则表示 Ngin…...

【前端扫盲】postman介绍及使用

Postman 是一款专为 API 开发与测试设计的 全流程协作工具&#xff0c;程序员可通过它高效完成接口调试、自动化测试、文档管理等工作。以下是针对程序员的核心功能介绍和应用场景说明&#xff1a; 一、核心功能亮点 接口请求构建与调试 支持所有 HTTP 方法&#xff08;GET/POS…...

Lua中os模块函数使用详解

目录 os.clock()os.date([format [, time]])os.difftime(t2, t1)os.execute(command)os.exit([code [, close]])os.getenv(varname)os.remove(filename)os.rename(oldname, newname)os.setlocale(locale [, category])os.time([table])os.tmpname()总结 以下是 Lua 中 os 模块的…...

量子计算与经典计算的拉锯战:一场关于计算未来的辩论

在计算科学领域&#xff0c;一场关于未来的激烈辩论正在上演。2025年3月&#xff0c;D-Wave量子公司的研究人员在《Science》杂志上发表了一项突破性成果&#xff0c;声称他们的量子退火处理器在几分钟内解决了一个经典超级计算机需要数百万年才能完成的复杂现实问题。这一声明…...

MySQL 基础入门

写在前面 关于MySQL的下载安装和其图形化软件Navicat的下载安装,网上已经有了很多的教程,这里就不再赘述了,本文主要是介绍了关于MySQL数据库的基础知识。 MySQL数据库 MySQL数据库基础 MySQL数据库概念 MySQL 数据库&#xff1a; 是一个关系型数据库管理系统 。 支持SQL语…...

GPT模型搭建

GPT模型搭建 1. 章节介绍 本章节聚焦于从0搭建GPT模型&#xff0c;通过事先准备的基础代码&#xff0c;引导学习者逐步构建模型。旨在让程序员、软件架构师和工程师等掌握GPT模型搭建的核心流程&#xff0c;理解其关键组件与技术细节&#xff0c;为实际应用和面试做好准备。 …...

BUUCTF-web刷题篇(8)

17.EasyCalcS 查看源码&#xff0c;发现有段代码有php文件&#xff0c;即calc.php 经过代码审计之后应该要访问calc.php文件&#xff0c;打开后&#xff1a; <?php error_reporting(0); if(!isset($_GET[num])){show_source(__FILE__); }else{$str $_GET[num];$blackli…...

AI SEO内容优化指南:如何打造AI平台青睐的高质量内容

AI SEO内容优化指南&#xff1a;如何打造AI平台青睐的高质量内容 在生成式AI平台&#xff08;如DeepSeek、Kimi、豆包、腾讯元宝等&#xff09;主导的搜索新时代&#xff0c;内容优化已成为企业抢占流量入口的核心策略。本文将从内容创作、分发到效果维护全链路&#xff0c;解…...

无需预对齐即可消除批次效应,东京大学团队开发深度学习框架STAIG,揭示肿瘤微环境中的详细基因信息

生物组织是由多种类型细胞构成的复杂网络&#xff0c;这些细胞通过特定的空间配置执行重要功能。近年来&#xff0c;10x Visium、Slide-seq、Stereo-seq 和 STARmap 等空间转录组学 (ST) 技术的进步&#xff0c;使得生物学家们能够在空间结构内绘制基因数据&#xff0c;从而各类…...

B2B2C多用户商城系统:打造新零售电商生态的创新解决方案

在当今数字化时代&#xff0c;电商行业正以前所未有的速度蓬勃发展&#xff0c;而新零售作为电商与传统零售的深度融合&#xff0c;正逐渐成为市场的新宠。为了满足这一变革带来的多元化需求&#xff0c;B2B2C多用户商城系统应运而生&#xff0c;为商家和消费者搭建了一个高效、…...

走向多模态AI之路(二):多模态 AI 如何工作?

目录 前言一、跨模态对齐&#xff08;Cross-modal Alignment&#xff09;&#xff1a;AI 如何理解不同模态的关系二、多模态融合&#xff08;Multimodal Fusion&#xff09;&#xff1a;AI 如何整合不同模态的信息三、多模态生成&#xff08;Multimodal Generation&#xff09;…...

MCP 实战:实现server端,并在cline调用

本文动手实现一个简单的MCP服务端的编写&#xff0c;并通过MCP Server 实现成绩查询的调用。 一、配置环境 安装mcp和uv, mcp要求python版本 Python >3.10; pip install mcppip install uv 二、编写并启用服务端 # get_score.py from mcp.server.fastmcp import…...

C#游戏开发【第18天】 | 深入理解队列(Queue)与栈(Stack):从基础到任务队列实战

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...

2.5路径问题专题:LeetCode 64. 最小路径和

动态规划解决最小路径和问题 1. 题目链接 LeetCode 64. 最小路径和 2. 题目描述 给定一个包含非负整数的 m x n 网格 grid&#xff0c;从网格的左上角出发&#xff0c;每次只能向右或向下移动一步&#xff0c;最终到达右下角。要求找到一条路径&#xff0c;使得路径上的数字…...

办公设备管理系统(springboot+ssm+jsp+maven)

基于springboot的办公设备管理系统(springbootssmjspmaven) 系统功能主要有&#xff1a; 欢迎页账号管理 管理员账号管理系统账号添加密码修改 普通管理员管理 用户管理用户添加用户查询 资产类型管理资产信息管理资产档案管理资产报表...

蓝桥杯2024JavaB组的一道真题的解析

文章目录 1.问题描述2.问题描述3.思路分析4.代码分析 1.问题描述 这个是我很久之前写的一个题目&#xff0c;当时研究了这个题目好久&#xff0c;发布了一篇题解&#xff0c;后来很多人点赞&#xff0c;我都没有意识到这个问题的严重性&#xff0c;我甚至都在怀疑自己&#xf…...

数据库--SQL

SQL&#xff1a;Structured Query Language&#xff0c;结构化查询语言 SQL是用于管理关系型数据库并对其中的数据进行一系列操作&#xff08;包括数据插入、查询、修改删除&#xff09;的一种语言 分类&#xff1a;数据定义语言DDL、数据操纵语言DML、数据控制语言DCL、事务处…...

SQL Server:Log Shipping 说明

目录标题 SQL Server Log Shipping与Oracle归档日志备份对比分析一、SQL Server Log Shipping的日志截断机制二、Oracle归档日志备份对比三、关键配置对比表四、最佳实践建议 如何修改和查看SQL Server默认备份配置防止自动删除&#xff1f;一、查看现有备份配置二、修改备份配…...

Zephyr实时操作系统初步介绍

一、概述 Zephyr是由Linux基金会托管的开源实时操作系统&#xff08;RTOS&#xff09;&#xff0c;专为资源受限的物联网设备设计。其核心特性包括模块化架构、跨平台兼容性、安全性优先以及丰富的连接协议支持。基于Apache 2.0协议&#xff0c;Zephyr允许商业和非商业用途的自…...

【大模型系列篇】大模型基建工程:基于 FastAPI 自动构建 SSE MCP 服务器 —— 进阶篇

&#x1f525;&#x1f525;&#x1f525; 上期 《大模型基建工程&#xff1a;基于 FastAPI 自动构建 SSE MCP 服务器》中我们使用fastapi-mcp自动挂载fastapi到mcp工具&#xff0c;通过源码分析和实践&#xff0c;我们发现每次sse请求又转到了内部fastapi RESTful api接口&…...

深度学习deeplearn3

# Jupyter Notebook魔法命令&#xff0c;用于在Notebook中内联显示图表 %matplotlib inline# 导入NumPy库&#xff0c;用于高效的数值计算 import numpy as np# 从matplotlib_inline库导入backend_inline模块&#xff0c;用于设置图表显示格式 from matplotlib_inline import b…...

(九)图形管线

一图说明问题 顶点数据->顶点着色器->细分着色器->几何着色器->光栅化->片元着色器->颜色混合 创建图形管线函数放在后面位置 void MyApplication::initVulkan() { createInstance(); createSurface(); pickPhysicalDevice(); createLogicalDevice(); cre…...

7-3 逆序的三位数

程序每次读入一个正3位数&#xff0c;然后输出按位逆序的数字。注意&#xff1a;当输入的数字含有结尾的0时&#xff0c;输出不应带有前导的0。比如输入700&#xff0c;输出应该是7。 输入格式&#xff1a; 每个测试是一个3位的正整数。 输出格式&#xff1a; 输出按位逆序…...

git从历史版本创建新分支或标签

git从某个历史版本创建标签 # 查看历史版本 git log git tag tag-v1.0 780e2a7fc714faf388ba71git从某个分支的指定历史版本中创建新分支 # 查看历史版本 git log # 从历史分支创建标签 git checkout -b new-branch 780e2a7fc714faf388ba71...

HTML 音频(Audio)学习笔记

一、HTML 音频概述 在 HTML 中&#xff0c;音频可以通过多种方式播放&#xff0c;但要确保音频在不同浏览器和设备上都能正常播放&#xff0c;需要掌握一些技巧。HTML5 引入了 <audio> 元素&#xff0c;为音频播放提供了一种标准方法&#xff0c;但在 HTML4 中&#xff…...

五种音频器件综合对比——《器件手册--音频器件》

目录 音频器件 简述 1. 扬声器&#xff08;Speakers&#xff09; 2. 麦克风&#xff08;Microphones&#xff09; 3. 放大器&#xff08;Amplifiers&#xff09; 4. 音频接口&#xff08;Audio Interfaces&#xff09; 5. 音频处理器&#xff08;Audio Processors&#xff09…...

数据结构复习(单调栈,单调队列,KMP,manacher,tire,字符串哈希)

单调栈&#xff1a; 介绍&#xff1a; 单调栈用于解决"寻找每个元素左侧/右侧第一个比它小/大的元素"类问题。栈中元素保持单调性&#xff0c;时间复杂度O(n)。 维护一个严格递增栈。对于每个元素a[i]&#xff0c;不断弹出栈顶比a[i]大的元素&#xff0c;剩下的栈顶即…...

(学习总结32)Linux 基础 IO

Linux 基础 IO 一、什么是 " 文件 "二、C 文件接口打开文件写文件读文件其它介绍 三、系统文件 I/O传递标志位系统接口写文件系统接口读文件部分系统调用接口介绍打开文件函数 open关闭文件函数 close写入文件函数 write读取文件函数 read 文件描述符 fdfd 0 & 1…...

操作系统(一):概念及主流系统全分析

目录 一.操作系统是什么 二.操作系统的分类 2.1 按应用场景分类 2.2 按实时性分类 2.3 按内核架构分类 2.4 按用户与任务分类 三.主流操作系统比较 四.未来趋势 一.操作系统是什么 操作系统&#xff08;Operating System, OS&#xff09;是计算机系统的核心软件&#x…...

三、GPIO

一、GPIO简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口GPIO引脚电平&#xff1a;0V&#xff08;低电平&#xff09;~3.3V&#xff08;高电平&#xff09;&#xff0c;部分引脚可容忍5V 容忍5V&#xff0c;即部分引脚输入5V的电压&#xff0c;…...

Ceph异地数据同步之-RBD异地同步复制(上)

#作者&#xff1a;闫乾苓 文章目录 前言基于快照的模式&#xff08;Snapshot-based Mode&#xff09;工作原理单向同步配置步骤单向同步复制测试双向同步配置步骤双向同步复制测试 前言 Ceph的RBD&#xff08;RADOS Block Device&#xff09;支持在两个Ceph集群之间进行异步镜…...

fastapi完全离线环境(无外网)的访问Swagger所做特殊处理

在互联网环境中&#xff0c;只要 启动FastAPI 服务运行在本地机器上&#xff0c;访问 http://localhost:8000/docs&#xff08;Swagger UI&#xff09;就可以访问到Swagger界面&#xff0c;但是在完全离线环境&#xff08;无外网&#xff09;下如何访问Swagger页面呢&#xff1…...

在网络中加入预训练的多层感知机(MLP)有什么作用?

在网络中加入预训练的多层感知机&#xff08;MLP&#xff09;通常是为了引入先验知识、提升特征表示能力或dropout&#xff0c;具体作用取决于MLP的设计和预训练任务。以下是常见的应用场景和优势&#xff1a; 1. 特征融合与迁移学习:预训练的MLP可以作为特征提取器&#xff0…...

3.2/Q2,GBD数据库最新文章解读

文章题目&#xff1a;Temporal trends in the burden of vertebral fractures caused by falls in China and globally from 1990 to 2021: a systematic analysis of the Global Burden of Disease Study 2021 DOI&#xff1a;10.1186/s13690-025-01500-y 中文标题&#xff1a…...

机器学习的一百个概念(9)学习曲线

前言 本文隶属于专栏《机器学习的一百个概念》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见[《机器学习的一百个概念》 ima 知识库 知识库广场搜索&…...

浅谈Tomcat数据源连接池

目录 为什么需要JDBC连接池 Tomcat JDBC Pool 相关参数 1. 基本配置 2. 连接池大小控制 3. 连接验证与测试 4. 空闲连接回收 5. 连接泄漏与超时 Tomcat JDBC Pool 源码分析&#xff08;tomcat 8.5.3&#xff09; DataSourceFactory DataSource ConnectionPool Pool…...

Techub 财报解读:Circle 冲刺 IPO,但收入增长难掩利润困局

作者&#xff1a;Techub 财报解读 撰文&#xff1a;Yangz&#xff0c;Techub News 4 月 1 日&#xff0c;Circle 向美国证券交易委员会&#xff08;SEC&#xff09;提交 S-1 文件&#xff0c;计划进行首次公开募股&#xff08;IPO&#xff09;&#xff0c;股票代码为 CRCL&…...

C++中的链表操作

在C中&#xff0c;链表是一种常见的数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含数据部分和指向下一个节点的指针。C标准库&#xff08;STL&#xff09;中提供了std::list和std::forward_list两种链表实现&#xff0c;分别对应双向链表和单向链表。此外&am…...

Vue2 生命周期

文章目录 前言&#x1f504; Vue2 生命周期流程&#xff08;8个核心钩子&#xff09;&#x1f4dd; 代码中典型用法示例一、您的描述验证二、完整生命周期代码示例三、关键阶段行为说明&#x1f50d; 常见问题 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案…...

2007-2022年 上市公司政府补助数据 -社科数据

上市公司政府补助数据&#xff08;2007-2022年&#xff09;-社科数据https://download.csdn.net/download/paofuluolijiang/90028547 https://download.csdn.net/download/paofuluolijiang/90028547 政府补助是指政府为支持企业发展&#xff0c;提供的资金或资源支持。对于上市…...

设计心得——状态机

一、状态机 在设计一些与硬件交互或者游戏等开发中&#xff0c;经常会听到状态机&#xff08;State Machines&#xff09;这个字眼&#xff0c;而在设计模式&#xff08;GoF&#xff09;中&#xff0c;又经常听到状态模式这个概念&#xff0c;它们之间有什么联系和不同呢&…...

python match case语法

学习路线&#xff1a;B站 普通的if判断 def if_traffic_light(color):if color red:return Stopelif color yellow:return Slow downelif color green:return Goelse:return Invalid colorprint(if_traffic_light(red)) # Output: Stop print(if_traffic_light(yellow)) …...

Lua中协程相关函数使用详解

目录 1. coroutine.create(f)2. coroutine.resume(co [, val1, ...])3. coroutine.yield([val1, ...])4. coroutine.status(co)5. coroutine.wrap(f)6. coroutine.running()7. coroutine.isyieldable()协程状态转换示例总结 Lua 中的协程&#xff08;coroutine&#xff09;提供…...

代码拟有感

最近的日子像被按了0.5倍速播放键。腱鞘炎让手腕转动时发出咯吱声&#xff0c;尾骨的钝痛让久坐变成酷刑&#xff0c;落枕的脖子和酸胀的手臂组成了“疼痛交响乐”——这些隐秘的、持续的身体抗议&#xff0c;让原本枯燥的代码练习变成了一场生理与意志的拉锯战。 我盯着屏幕苦…...

《实战AI智能体》MCP对Agent有哪些好处

首先MCP为Agent提供了标准化的方式来接入各种工具和数据源,无论是本地运行的工具,例如通过stdio服务器,还是远程托管的服务HTTP over SSE服务, Agent都可以通过统一的接口与它们进行交互,极大扩展了第三方工具库。 例如,在金融领域,Agent 可以接入股票分析的MCP工具。当…...

maptalks获取所有图层并把图层按照zIndex排序

maptalks获取所有图层并把图层按照zIndex排序 获取所有图层 通过调用 map.getLayers() 可以返回当前地图上所有的图层集合。此方法会返回一个数组形式的结果&#xff0c;其中包含了地图上的每一个图层层级对象。 图层属性中的 ZINDEX 每种图层类型&#xff08;如矢量图层、…...

GUI-Guider 按钮按下 选项卡 右移动一个,到最右边停下

extern lv_ui guider_ui; // 在文件顶部添加// 在按钮事件中使用&#xff1a; lv_obj_t * tabview guider_ui.screen_tabview_1; // 替换为你的实际 TabView 名称 uint16_t current lv_tabview_get_tab_act(tabview); lv_tabview_set_act(tabview, current 1, LV_ANIM_ON); …...

让AI再次伟大-MCP-Client开发指南

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理、AI应用&#x1f525;如果感觉…...

sql工具怎么选?

为什么大多数主流工具又贵又难用&#xff1f; 有没有一款免费好用的sql工具&#xff1f; 像大多人朋友常用的sql工具&#xff0c;应该都遇到过这种情况&#xff0c; 用着用着收到了来自品牌方的律师函&#xff0c; 或者处理数据经常卡死&#xff0c; 再或者不支持国产数据库…...