【MySQL】C语言连接数据库

文章目录

  • 一、安装 MySQL 库
  • 二、MySQL C API 相关接口
    • 1、C API 官方文档
    • 2、初始化 MYSQL
    • 3、连接 MySQL
    • 4、下发 mysql 指令
    • 5、获取 mysql 查询结果
    • 6、释放 MYSQL_RES 对象
    • 7、关闭 MySQL 连接
    • 8、MySQL 其他操作
    • 9、总结
  • 三、使用图形化工具连接 MySQL

一、安装 MySQL 库

我们之前学习数据库都是在 Linux 的 mysql 客户端下以纯命令行的方式操作的,但其实,我们也可以使用 C/C++/Java/Python 等语言来连接数据库,向 mysqld 下达 sql 语句并获取执行结果。不过,在这之前,我们需要先安装 MySQL 对应的库,这里我们以 C 语言连接数据库为例。

关于 MySQL 的 C语言库,我们可以直接到 MySQL 官网中去下载,然后 rz 上传到 Linux 中解压。当然我们也可以通过 yum 来直接安装 mysql client 以及 mysql devel,因为之前我们在安装 mysql-commun-server 时已经配置了 mysql 相关的 yum 源。(其实那时候 mysql client 我们也已经安装了)image-20231023210545704

image-20231023210618536

image-20231023210632613

安装完毕后我们就可以在 /usr/include/mysql 目录下找到 mysql 相关的头文件了:image-20231023211101489

同时,我们也可以在 /lib64/mysql/ 以及 /usr/lib64/mysql 目录下找到 mysql 对应的动态库以及静态库了:image-20231023211305132

验证引入是否成功

现在,我们就可以使用 mysql 目录下头文件中提供的相关函数来连接数据库了。

不过,在正式连接数据库之前,我们可以先通过 mysql_get_client_info() 函数来验证一下 mysql 相关头文件以及动态库是否被成功引入:

函数原型:const char *mysql_get_client_info(void);
返回值: A character string that represents the MySQL client library version.
#include <iostream>
#include <mysql/mysql.h>
using namespace std;int main()
{cout << "mysql version: " << mysql_get_client_info() << endl;return 0;
}

image-20231023214201942

这里有几个需要注意的地方:

  1. 由于我们要使用 mysql C库中的函数,所以在 test.cc 中我们需要包含 mysql 相关头文件。
  2. 在程序编译时,我们需要使用 -l 选项来指定我们要链接的 mysql 动态库,并且动态库的库名称是去掉前缀 lib 以及后缀 .so 后的剩余部分。(libmysqlclient.so -> mysqlclient)
  3. 由于动态库在 /usr/lib64/mysql/ 目录下,而系统的默认库路径是 /usr/lib64/,所以我们还需要使用 -L 选项来指定动态库的路径。
  4. mysql C语言相关头文件在 /usr/include/mysql/ 目录下,而系统默认的头文件搜索路径是 /usr/include/,所以按道理来说,我们也是需要使用 -I 选项指明头文件路径的;但这里由于我们在编写源程序,包含头文件时使用的是 mysql/mysql.h,而不仅仅是 mysql.h,所以不需要指定。
  5. 最后,关于动静态库相关的知识,我们其实以前在 Linux 系统编程中讲过,有需要的同学可以再看一下 – 动静态库。

二、MySQL C API 相关接口

1、C API 官方文档

关于C语言连接数据所涉及到的各种数据结构的介绍以及相关函数的使用其实在 MySQL C API 官方文档中已经给出了,我们可以通过它来快速了解并上手 MySQL C API。image-20231029131432088

image-20231029131530338

2、初始化 MYSQL

要使用 MySQL C语言库,需要先使用 mysql_init 函数完成对 MYSQL 结构体指针的初始化工作。

MYSQL *mysql_init(MYSQL *mysql)
  • 函数返回值:失败返回 NULL。

注意:mysql_init 函数的参数以及返回值都是 MYSQL 指针类型,对于 MYSQL,大家把它类比到C语言中的文件指针来理解即可。MYSQL 和C语言文件 FILE 一样,本质上都是一个结构体。image-20231029133239373

image-20231029133254539

MYSQL *mfp = mysql_init(nullptr);
if(mfp == nullptr)
{cerr << "mysql init error" << endl;return 1;
}
cout << "mysql init success" << endl;

image-20231029140828078

注意:这里用C语言的 NULL 还是C++的 nullptr 都可以,因为它们在数值上都是0;区别在于在定义时 NULL 是一个整数,而 nullptr 则是被强转为了 void* 类型。

3、连接 MySQL

初始化完毕后,我们需要使用 mysql_real_connect 函数来连接数据库。

MYSQL *
mysql_real_connect(MYSQL *mysql,       // MYSQL结构体指针对象const char *host,   // mysqld服务进程所在的主机const char *user,   // 登录MySQL的用户const char *passwd, // 用户密码const char *db,     // 要访问的数据库unsigned int port,  // mysqld服务进程的端口号const char *unix_socket,    // 默认设为NULL即可unsigned long client_flag)  // 默认设为0即可
  • 函数返回值:失败返回0,成功返回传入的MYSQL指针。
const string host = "127.0.0.1";
const string user = "thj";
const string password = "Abcd1234@";
const string db = "test_connection";
unsigned int port = 4106;
mfp = mysql_real_connect(mfp, host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, nullptr, 0);
if(mfp == nullptr)
{cerr << "mysql connection error" << endl;return 2;
}
cout << "mysql connection success" << endl;

image-20231029140931672

其实从这里我们也可以看出 MYSQL 其实就是一个结构体,其中包含了 host、user、port 等字段,我们调用 mysql_real_connect 函数时传递的参数就是用来填充这些字段的。image-20231029141529470

设置连接字符集

需要注意的是,我们之前在创建数据库时默认使用的字符集是 utf8,而C语言连接数据时默认的字符集是 latin1 的,这就会导致我们在向表中插入中文数据时,由于字符集不匹配,最终数据库中存储的数据显式出来是乱码。

所以,我们需要使用 mysql_set_character_set 函数设置连接字符集为 utf8

int mysql_set_character_set(MYSQL *mysql, const char *csname)
  • 函数返回值:返回0表示成功,非0表示失败。
int n = mysql_set_character_set(mfp, "utf8");
if(n != 0) { cout << "warning: character set fail" << endl; }

4、下发 mysql 指令

在成功连接到数据库之后,我们就可以通过 mysql_query 函数来下发 mysql 指令了。

int mysql_query(MYSQL *mysql, const char *stmt_str)
  • 函数返回值:执行成功返回0,失败返回非0。
string sql;
while(true)
{cout << "mysql>>> ";getline(cin, sql);int n = mysql_query(mfp, sql.c_str());if(n != 0) { cout << sql << " fail" << endl; }else cout << sql << " success" << endl;
}

image-20231029144642043

我们可以登录 msyql 客户端查看数据是否真正被插入:image-20231029144749785

需要注意的是,我们在使用 mysql client 时,一条 sql 语句需要以分号结尾;但是在C语言中,sql 语句可以不用带分号,当然带上也没事。

5、获取 mysql 查询结果

我们上面是对数据库执行增删改操作,它们相对来说比较简单,因为我们只需要将指令下发给数据库即可,后面的事情我们不必关心。但如果我们执行的是查询操作,则需要通过 mysql_store_result 函数来获取查询结果。

MYSQL_RES *mysql_store_result(MYSQL *mysql)
  • 函数返回值:失败返回 NULL,成功返回一个非空的 MYSQL_RES 类型的结构体指针。

实际上,mysql_store_result 函数会调用 MYSQL 结构体变量中的 st_mysql_methods 字段中的 read_rows 函数指针来获取查询的结果;然后将查询结果保存到 MYSQL_RES 结构体中并返回结构体指针。这样,当执行完 mysql_store_result 以后,其实数据都已经在MYSQL_RES 变量中了,我们直接从中获取即可。

需要注意的是,MYSQL_RES 是通过 malloc/new 空间的方式来保存查询结果的,所以当我们使用完毕之后,一定要记得释放 MYSQL_RES 对象,否则就会造成内存泄漏。同时,MYSQL_RES 结构体中存在查询结果的列数、列信息、行数、行内容等属性,我们需要使用对应的函数来获取这些信息。image-20231029152423987

  • 获取结果列数。
unsigned int mysql_num_fields(MYSQL_RES *result)
  • 获取结果中每一列的列属性。
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *res);

关于 MYSQL_FIELD 结构体,它里面包含了列的各种属性信息,包括列名称、列类型、列大小、列属于哪个表哪个库等等。image-20231029153331696

同时,我们可以通过重复调用 mysql_fetch_field 函数来获取表中每个列字段的 MYSQL_FIELD 结构,即当我们下次再调用 mysql_fetch_field 函数时,会自动获取到表中下一个列的属性信息,而不需要我们手动指定访问的是哪一列。这和C++中的迭代器很类似。 这种类似迭代器的功能应该是与 MYSQL_RES 中的 current_field 字段有关。

当然,我们也可以通过调用 mysql_fetch_fields 函数一次获取到所有列的属性信息,然后分别打印。

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);
  • 获取结果行数。
my_ulonglong mysql_num_rows(MYSQL_RES *result)
  • 获取结果中每一行的具体内容。
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)

MYSQL_ROW 本质上其实是一个二级指针,我们可以把它当作一个一级指针数组来看待,数组中的每个元素都是一级指针。同时,由于 MYSQL_RES 中保存的是查询到的多行结果,所以我们可以将 MYSQL_RES 看作是一个二级指针数组,数组中的每个元素都是二级指针 (MYSQL_ROW)image-20231029161945208

image-20231029163936711

如上,将 MYSQL_RES 当作一个二维数组,那么 MYSQL_RES 中的每一个元素就代表查询结果中的一行数据 (不包含属性行),这行数据是一个一维数组,且数组中的每个元素都是 char* 类型 (mysql 在读取数据时会将所有的数据都当作字符串)。这样,我们就可以先使用 mysql_num_rows 和 mysql_num_fields 获取到结果集的行数和列数,然后以遍历二维数组的方式即可获取到全部行的内容了

具体示例如下:

// 下发mysql指令 -- 查询
string sql = "select * from user";
if (mysql_query(mfp, sql.c_str()) != 0)
{ cout << sql << " fail" << endl; 
}
else cout << sql << " success" << endl;// 将查询结果转储到MYSQL_RES中
MYSQL_RES *res = mysql_store_result(mfp);
if(res == nullptr)
{cerr << "store query result error" << endl;return 3;
}// 获取结果集的行数与列数
size_t rowCount = mysql_num_rows(res);
size_t colCount = mysql_num_fields(res);// 打印列属性信息 -- 一次获取单列
for(int i = 0; i < colCount; i++)
{// 一个列字段的所有属性 -- 自动迭代MYSQL_FIELD *field = mysql_fetch_field(res);cout << field->name << '\t';
}
cout << endl;// 一次获取全部列字段的属性信息,然后分别打印
// MYSQL_FIELD *total_fields = mysql_fetch_fields(res);
// for(int i = 0; i < colCount; i++)
// {
//     cout << total_fields[i].name << '\t';
// }
// cout << endl;// 打印结果集中的行内容
for(int i = 0; i < rowCount; i++)
{// 一行的所有内容 -- 自动迭代MYSQL_ROW row = mysql_fetch_row(res);for(int j = 0; j < colCount; j++){// 一行内容中的某一列的内容cout << row[j] << '\t';}cout << endl;
}

image-20231029173057936

6、释放 MYSQL_RES 对象

由于 MYSQL_RES 保存查询结果的空间是通过 malloc/new 得到的,所以当我们使用完毕后需要释放掉 MYSQL_RES 对象,防止内存泄露。

void mysql_free_result(MYSQL_RES *result)
mysql_free_result(res);

7、关闭 MySQL 连接

最后,当我们使用完 MySQL 后,需要关闭 MySQL 之前建立的连接。

void mysql_close(MYSQL *sock);
mysql_close(mfp);

8、MySQL 其他操作

除了上述这些操作外,MySQL C API 还支持事务、回滚等常见操作,感兴趣的同学可以了解一下。

my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode);
my_bool STDCALL mysql_commit(MYSQL * mysql);
my_bool STDCALL mysql_rollback(MYSQL * mysql);

9、总结

使用 MySQL C API 连接数据库进行简单操作的步骤如下:

  1. 初始化 MYSQL 结构体指针 – mysql_init。
  2. 连接 MySQL – mysql_real_connect:需要指定数据库服务所在主机、端口以及登录mysql的用户和密码等信息。
  3. 下发 MySQL 指令 – mysql_query。
  4. 获取 MySQL 查询结果:将查询结果转储到 MYSQL_RES 中 – mysql_store_result,获取查询结果的行数 – mysql_num_rows,获取查询结果列数 – mysql_num_fields,获取单个/所有列字段的 MYSQL_FIELD 属性信息 – mysql_fetch_field/mysql_fetch_fields,获取查询结果单行的内容 (不包含属性行) – mysql_fetch_row。
  5. 释放 MYSQL_RES 对象 – mysql_free_result。
  6. 关闭 MySQL 连接 – mysql_close。
#include <iostream>
#include <mysql/mysql.h>
using namespace std;int main()
{// 验证C库是否引入成功// cout << "mysql version: " << mysql_get_client_info() << endl;// 初始化MYSQL指针MYSQL *mfp = mysql_init(nullptr);if(mfp == nullptr){cerr << "mysql init error" << endl;return 1;}cout << "mysql init success" << endl;// 连接数据库const string host = "127.0.0.1";const string user = "thj";const string password = "Abcd1234@";const string db = "test_connection";unsigned int port = 4106;mfp = mysql_real_connect(mfp, host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, nullptr, 0);if(mfp == nullptr){cerr << "mysql connection error" << endl;return 2;}cout << "mysql connection success" << endl;// 设置连接字符集int n = mysql_set_character_set(mfp, "utf8");if(n != 0) { cout << "warning: character set fail" << endl; }// 下发mysql指令 -- 增删改// string sql;// while(true)// {//     cout << "mysql>>> ";//     getline(cin, sql);//     int n = mysql_query(mfp, sql.c_str());//     if(n != 0) //     { //         cout << sql << " fail" << endl; //     }//     else cout << sql << " success" << endl;// }// 下发mysql指令 -- 查询string sql = "select * from user";if (mysql_query(mfp, sql.c_str()) != 0){ cout << sql << " fail" << endl; }else cout << sql << " success" << endl;// 将查询结果转储到MYSQL_RES中MYSQL_RES *res = mysql_store_result(mfp);if(res == nullptr){cerr << "store query result error" << endl;return 3;}// 获取结果集的行数与列数size_t rowCount = mysql_num_rows(res);size_t colCount = mysql_num_fields(res);// 打印列属性信息 -- 一次获取单列for(int i = 0; i < colCount; i++){// 一个列字段的所有属性 -- 自动迭代MYSQL_FIELD *field = mysql_fetch_field(res);cout << field->name << '\t';}cout << endl;// 一次获取全部列字段的属性信息,然后分别打印// MYSQL_FIELD *total_fields = mysql_fetch_fields(res);// for(int i = 0; i < colCount; i++)// {//     cout << total_fields[i].name << '\t';// }// cout << endl;// 打印结果集中的行内容for(int i = 0; i < rowCount; i++){// 一行的所有内容 -- 自动迭代MYSQL_ROW row = mysql_fetch_row(res);for(int j = 0; j < colCount; j++){// 一行内容中的某一列的内容cout << row[j] << '\t';}cout << endl;}// 释放MYSQL_RES对象mysql_free_result(res);// 关闭数据库连接mysql_close(mfp);return 0;
}

三、使用图形化工具连接 MySQL

其实除了使用各种编程语言来连接数据库之外,在实际开发中另一种比较常用的方式是使用图形化工具来连接数据库。

市场上关于 MySQL 的图形化工具有很多,其中比较优秀的是 Navicat 和 SQLyog,但他们都是收费的,当然如果个人使用的话可以在网上下载破解版的。免费的工具也有很多,但大都不怎么好用,在免费工具中表现比较优秀的是 MySQL 官方开发的 Workbench。如果大家有兴趣的话可以去尝试一下,这里我仅仅简单提一下。

相关文章阅读推荐:https://blog.csdn.net/wpc2018/article/details/122862956


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

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

相关文章

.jnlp

首先配置电脑的java环境。 百度搜索jre下载&#xff0c;会有很多结果&#xff0c;一般选择官网进行下载。 下载正确的jre版本。 我的电脑是windows 64位&#xff0c;根据你自己电脑的情况选择版本进行下载。不懂自己电脑是多少位的可以看下一步。 查看电脑是64位还是32…

【RabbitMQ 实战】12 镜像队列

一、镜像队列的概念 RabbitMQ的镜像队列是将消息副本存储在一组节点上&#xff0c;以提高可用性和可靠性。镜像队列将队列中的消息复制到一个或多个其他节点上&#xff0c;并使这些节点上的队列保持同步。当一个节点失败时&#xff0c;其他节点上的队列不受影响&#xff0c;因…

【多线程面试题十九】、 公平锁与非公平锁是怎么实现的?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a; 公平锁与非公平锁是怎么…

网络安全—小白自学

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

【智能座舱系列】- 深度解密小米Hyper OS,华为HarmonyOS区别

上一篇文章《小米的澎湃OS到底牛不牛?与鸿蒙系统之间差距有多大》,从多个方面比较了小米Hyper OS 与 华为HarmonyOS的区别,本篇文章继续从架构层面深度解读两者本质的区别。 小米澎湃OS是“以人为中心,打造人车家全生态操作系统”,该系统基于深度进化的Android以及自研的V…

低代码软件在酒店行业的应用:提升效率与创新!

疫情放开后&#xff0c;旅游业开始兴盛发展&#xff0c;酒店行业也恢复了疫情前的繁忙。但是由于管理架构上的不完善导致很多酒店并不能很好地承接巨大的客流量&#xff0c;而消费者在旅游过程对体验要求是最高的&#xff0c;所以酒店拥有一个能够高效运营的管理系统至关重要。…

高等数学啃书汇总重难点(八)向量代数与空间解析几何

持续更新&#xff0c;高数下第一章&#xff0c;整体来说比较简单&#xff0c;但是需要牢记公式&#xff0c;切莫掉以轻心~ 一.向量平行的充要条件 二.向量坐标的线性运算 三.向量的几何性质 四.数量积 五.向量积 六.混合积 七.曲面方程 八.空间曲线方程 九.平面的点法式方程 十…

Linux高性能服务器编程——ch8笔记

第8章 高性能服务器程序框架 8.1 服务器模型 服务器启动后&#xff0c;首先创建一个&#xff08;或多个&#xff09;监听socket&#xff0c;并调用bind函数将其绑定到服务器感兴趣的端口&#xff0c;然后调用listen函数等待客户连接。服务器稳定运行之后&#xff0c;客户端就可…

Linux启动之uboot分析

Linux启动之uboot分析 uboot是什么&#xff1f;一、补充存储器概念1.存储器种类1.norflash - 是非易失性存储器&#xff08;也就是掉电保存&#xff09;2.nandflash - 是非易失性存储器&#xff08;也就是掉电保存&#xff09;3.SRAM - 静态随机访问存储器 - Static Random Acc…

如何在宝塔面板安装配置MySQL数据库并实现公网访问

宝塔安装MySQL数据库&#xff0c;并内网穿透实现公网远程访问 文章目录 宝塔安装MySQL数据库&#xff0c;并内网穿透实现公网远程访问前言1.Mysql服务安装2.创建数据库3.安装cpolar3.2 创建HTTP隧道 4.远程连接5.固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网…

【鸿蒙软件开发】ArkTS基础组件之Select(下拉菜单)、Slider(滑动条)

文章目录 前言一、Select下拉菜单1.1 子组件1.2 接口参数 1.3 属性1.4 事件1.5 示例代码 二、Slider2.1 子组件2.2 接口参数&#xff1a;SliderStyle枚举说明 2.3 属性2.4 事件SliderChangeMode枚举说明 2.5 示例代码 总结 前言 Select组件&#xff1a;提供下拉选择菜单&#…

什么是α测试β测试和灰度测试?

吃软件测试这碗饭的&#xff0c;如果基础理论都不懂&#xff0c;谈何长久&#xff1f; 欢迎来学习本系列&#xff0c;基础理论比较枯燥&#xff0c;这也是为什么现在很少人掌握的主要原因。热饭尽量用浅显易懂 生动的例子 来帮助大家学习基础理论&#xff0c;所以请耐心看完此系…

【Linux】:Linux开发工具之Linux编辑器vim的使用

&#x1f52b;1.Linux编辑器-vim使用 &#x1f4e4; vi/vim的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是vim是vi的升级版本&#xff0c;它不仅兼容vi的所有指令&#xff0c;而且还有一些新的特性在里面。例如语法加亮&#xff0c;可视化操作不仅可以…

关于Anaconda及其镜像源的相关问题

1. 创建的虚拟环境中没有bin文件 conda create -n test_env请在上诉代码后添加对应的python对应版本&#xff0c;即可创建成功 conda create -n test_env python3.82. 关于anaconda中镜像源的相关操作 设置pip的全局索引源为阿里云镜像&#xff08;注意是全局索引&#xff0…

“软件开发报价混乱?看这一篇就够了!“

大家好&#xff0c;今天我们要聊一聊软件开发报价的那些事儿。相信很多企业和个人都曾为此犯过愁&#xff0c;看着报价单上一串串数字&#xff0c;心里直犯嘀咕&#xff1a;这价格靠谱吗&#xff1f;是不是被忽悠了&#xff1f;别急&#xff0c;今天我们就来揭开软件开发报价的…

linux 模块安装与卸载

文章目录 模块实现编译模块的 makefile编译报错解决模块编译日志自动化模块安装模块卸载配置头文件路径C/C 插件clangd 插件 模块实现 新建 my_module.c 文件 #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> #include <l…

Flutter报错RenderBox was not laid out: RenderRepaintBoundary的解决方法

文章目录 报错问题分析问题原因 解决办法RenderBox was not laid out错误的常见原因常见原因解决方法 RenderRepaintBoundaryRenderRepaintBoundary用途 报错 RenderBox was not laid out: RenderRepaintBoundary#d4abf relayoutBoundaryup1 NEEDS-PAINT NEEDS-COMPOSITING-BI…

海南海口大型钢结构件3D扫描全尺寸三维测量平面度平行度检测-CASAIM中科广电

高精度三维扫描技术已经在大型工件制造领域发挥着重要作用&#xff0c;特别是在质量检测环节&#xff0c;高效、高精度&#xff0c;可以轻松实现全尺寸三维测量。本期&#xff0c;CASAIM要分享的应用是在大型钢结构件的关键部位尺寸及形位公差检测。 钢结构件&#xff0c;是将…

功能型前端项目技术栈选型

PC功能型官网技术栈选择 vue2vuexvue-routerxaxiosanimate主推&#xff1a;vue3piniavue-routertypeScriptaxiosanimate&#xff08;新技术后期踩坑多&#xff0c;成本较高&#xff09; 1.2 vue3对比vue2 团队已经熟悉 Vue 2&#xff0c;并且官网的规模不是很大&#xff0c;Vue…

使用 Visual Studio Code 编写 TypeScript程序

安装 TypeScript 首先&#xff0c;确保你已经安装了 TypeScript&#xff0c;如果没有安装&#xff0c;请参考https://blog.csdn.net/David_house/article/details/134077973?spm1001.2014.3001.5502进行安装 创建 新建一个文件夹&#xff0c;用vs code打开&#xff0c;在文…