C语言与sqlite3入门
c语言与sqlite3入门
- 1 sqlite3数据类型
- 2 sqlite3指令
- 3 sqlite3的sql语法
- 3.1 创建表create
- 3.2 删除表drop
- 3.3 插入数据insert into
- 3.4 查询select from
- 3.5 where子句
- 3.6 修改数据update
- 3.7 删除数据delete
- 3.8 排序Order By
- 3.9 分组GROUP BY
- 3.10 约束
- 4 c语言执行sqlite3
- 4.1 下载c源码
- 4.2 cmake编译运行
- 5 创建或打开数据库
- 6 sqlite3_exec
- 7 sqlite3_prepare
- 7.1 sqlite3_prepare_v2
- 7.2 sqlite3_bind
- 7.3 sqlite3_step
- 7.4 sqlite3_column
- 7.5 sqlite3_reset
- 8 读写blob型数据
- 参考
1 sqlite3数据类型
- NULL 空
- INTEGER 整形
- REAL 浮点
- TEXT 文本
- BLOB binary large object二进制对象,一般存图像,声音,自定义结构体
2 sqlite3指令
sqlite3 test.db # 打开数据库, 没有就创建.databases #查看所有的数据库位置。
3 sqlite3的sql语法
3.1 创建表create
CREATE TABLE COMPANY(ID INT PRIMARY KEY NOT NULL,NAME TEXT NOT NULL,AGE INT NOT NULL,ADDRESS CHAR(50),SALARY REAL
);
3.2 删除表drop
DROP TABLE COMPANY;
3.3 插入数据insert into
INSERT INTO COMPANY VALUES (7, 'James', 24, 'Houston', 10000.00 );
或者
INSERT INTO COMPANY(id, name, age, address, salary) VALUES (7, 'James', 24, 'Houston', 10000.00 );
用第二种更严谨一些
假如没有设置值,为NULL或者0
INSERT INTO COMPANY(ID, name, age) VALUES (8, '张三', 11);
3.4 查询select from
SELECT ID, NAME, SALARY FROM COMPANY ;
3.5 where子句
select * from
与where name like 'a%'
都是会查询所有表的内容,一般禁用。
逻辑与或子句
SELECT * FROM COMPANY WHERE AGE >= 25 OR SALARY >= 65000
不为空
查询age不为空的记录
SELECT * FROM COMPANY WHERE AGE IS NOT NULL
模糊查询
所有名字以ki开头的
SELECT * FROM COMPANY WHERE NAME LIKE 'Ki%';
in
年龄为25或27的记录
SELECT * FROM COMPANY WHERE AGE IN ( 25, 27 );
年龄不为25且不为27
SELECT * FROM COMPANY WHERE AGE NOT IN ( 25, 27 );
子查询
年龄大于所有65000薪水以上员工年龄的记录
SELECT * FROM COMPANY WHERE AGE > (SELECT AGE FROM COMPANY WHERE SALARY > 65000);
3.6 修改数据update
UPDATE COMPANY SET ADDRESS = 'Texas' WHERE ID = 6;
3.7 删除数据delete
DELETE FROM COMPANY WHERE ID = 7;
3.8 排序Order By
其实默认就是升序,ASC是升序,DESC就是降序。
SELECTselect_list
FROMtable
ORDER BYcolumn_1 ASC,column_2 DESC;
3.9 分组GROUP BY
比如可以按照年龄来分组,看看不同年龄的平均薪资。
SELECT AGE, avg(SALARY) from COMPANY GROUP BY AGE;
3.10 约束
CREATE TABLE COMPANY(ID INT PRIMARY KEY NOT NULL,NAME TEXT NOT NULL UNIQUE,AGE INT NOT NULL CHECK(AGE > 0),ADDRESS CHAR(50),SALARY REAL DEFAULT 50000.00
);
主键约束:PRIMARY KEY,ID作为主键,不能有重复值,一般也不能为NULL。
NOT NULL: 不为空,该列不能有NULL
CEHCK 添加修改记录时,需要符合check条件。
DEFAULT 设置默认值。
4 c语言执行sqlite3
4.1 下载c源码
打开 c源码sqlite3下载页面 下载其中的source code源码,下第一个就好。
放入项目的sqlite文件夹中,除开我已经创建的两个数据库,项目结果应该长这样。
随便写一个c,获取sqlite3版本
#include <stdio.h>
#include "sqlite3.h"
int main(void)
{printf("%s\n", sqlite3_libversion());return 0;
}
4.2 cmake编译运行
在CMakeLists.txt中写
cmake_minimum_required (VERSION 3.5)project(test)
add_definitions("-Wall -g")include_directories (sqlite)add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/test.c ${PROJECT_SOURCE_DIR}/sqlite/sqlite3.c)
target_link_libraries (${PROJECT_NAME} pthread dl)add_executable(sqliteShell ${PROJECT_SOURCE_DIR}/sqlite/shell.c ${PROJECT_SOURCE_DIR}/sqlite/sqlite3.c)
target_link_libraries (sqliteShell pthread dl)
写好后cd打开build文件夹执行cmake和makefile
cmake .. & make
# 再执行test
./test
假如没有修改文件结构(增删文件/修改文件位置),只是修改了文件内容。
再次编译代码不需要再次运行cmake了,运行make即可
make
./test
5 创建或打开数据库
sqlite3_open
函数,打开数据库,没有就创建一个。
第一个参数就是数据库位置,相对位置是相对于程序执行时的位置,不是c文件所在位置
第二个是双指针的通道
sqlite3 *db = NULL;
int rc = sqlite3_open("../test.db", &db);
关闭
sqlite3_close(db);
如下方就可以创建一个表,并且插入一些值来使用
#include <stdio.h>
#include "sqlite3.h"
int main(void)
{sqlite3 *db = NULL;char *err_msg = NULL;int rc = sqlite3_open("../test.db", &db);if(rc != SQLITE_OK){fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));sqlite3_close(db);return 1;}const char *sql = "DROP TABLE IF EXISTS Cars;" "CREATE TABLE Cars(Id INT, Name TEXT, Price INT);" "INSERT INTO Cars VALUES(1, 'Audi', 52642);" "INSERT INTO Cars VALUES(2, 'Mercedes', 57127);" "INSERT INTO Cars VALUES(3, 'Skoda', 9000);" "INSERT INTO Cars VALUES(4, 'Volvo', 29000);" "INSERT INTO Cars VALUES(5, 'Bentley', 350000);" "INSERT INTO Cars VALUES(6, 'Citroen', 21000);" "INSERT INTO Cars VALUES(7, 'Hummer', 41400);" "INSERT INTO Cars VALUES(8, 'Volkswagen', 21600);";rc = sqlite3_exec(db, sql, NULL, NULL, &err_msg);if(rc != SQLITE_OK){fprintf(stderr, "SQL error: %s\n", err_msg);sqlite3_free(err_msg);sqlite3_close(db);return 1;}sqlite3_close(db);return 0;}
6 sqlite3_exec
sqlite3_exec是执行sql语句的函数,算是最重要的函数。
sqlite3*, //数据库
const char* sql,//sql语句
*callback, //回调
void* data, //回调的参数
char **errmsq //错误信息
const char * = "SELECT * FROM car";
char* dataName = "test";
char *err_msg = NULL;
int rc = sqlite3_exec(db, sql, callback, dataName, &err_msg);int callback(void* para, int columnCount, char** columnValue, char** columnName){}
callback在每查询到一行数据的时候就调用一次,所以每次得到的是一行数据。
其中callback只能自己传一个参数,但是自身有4个参数。
- para 传来的参数
- columnCount 列数
- columnValue 一维的字符串数组,保存的是每一列数据。
- columnName 一维字符串数组,列名。
比如下方获取所有的test.db中的数据,打印出来。
#include <stdio.h>
#include "sqlite3.h"int callback(void *, int, char **, char **);int main(void)
{sqlite3 *db = NULL;char *err_msg = NULL;int rc = sqlite3_open("../test.db", &db);if (rc != SQLITE_OK) {fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));sqlite3_close(db);return 1;}const char *sql = "SELECT * FROM Cars";char* dataName = "test";rc = sqlite3_exec(db, sql, callback, dataName, &err_msg);if (rc != SQLITE_OK ) {fprintf(stderr, "Failed to select data\n");fprintf(stderr, "SQL error: %s\n", err_msg);sqlite3_free(err_msg);sqlite3_close(db);return 1;}sqlite3_close(db);return 0;
}int callback(void* para, int columenCount, char** columnValue, char** columnName)
{for (int i = 0; i < columenCount; ++i){printf("%s = %s\n", columnName[i], (columnValue[i] ? columnValue[i] : "NULL"));}printf("\n");return 0;
}
7 sqlite3_prepare
exec使用起来简单,它在执行的过程中,有一个编译再执行的过程。
假如有多个insert语句,exec需要每inset一次都需要编译一次,效率低。
对于结构相同的语句,我们是否可以先编译,于是有了一个prepare,先编译,再插入变量执行。
最开始有一个控制变量sqlite3_stmt的句柄,其中stmt的全称应该是statement。
sqlite3_stmt *pstmt;
7.1 sqlite3_prepare_v2
先需要准备一个模板
int sqlite3_prepare_v2(sqlite3 *db, /* 数据库通道 */const char *zSql, /* sql语句 */int nByte, /* sql语句长度,一般填入-1自动计算 */sqlite3_stmt **ppStmt, /* 准备语句的控制权柄 */const char **pzTail /* sql语句超出了nByte后存放位置,一般把nByte设置足够大,这个设置为NULL即可 */
);
下面是一个模板的代码,将插入语句设置为模板,其中需要插入的内容用?代替
sqlite3_stmt *pStmt = NULL;
char *pzTail = NULL;
const char *sql = "INSERT INTO person(name, age, sex) VALUES(?,?,?);";
rc = sqlite3_prepare_v2(pdb, sql, strlen(sql), &pStmt, pzTail);
用prepare语句后可以先编译。
7.2 sqlite3_bind
这个函数就是设置插入值。
有三个函数,用于插入不同类型值。
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_doubule(sqlite3_stmt*, int, double);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int, void(*)(void*));
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int, void(*)(void*))
- 句柄handle
- 需要赋值的是sql语句中的第几个参数,从1开始。
- 插入值,text和blob是指针。
- 插入值长度(strlen/sizeof)。
- 绑定blob类型的析构函数,一般可以设置为NULL
那么现在我们需要插入值来形成一个sql语句就可以这么写
const char * name = "iceylia";
age = 100;
sex = "未知";
sqlite3_bind_text(pstmt, 1, name, strlen(name), NULL);
sqlite3_bind_int(pstmt, 2, age);
sqlite3_bind_text(pstmt, 3, sex, strlen(sex), NULL);
7.3 sqlite3_step
插入值后执行sql语句,用sqlite3_step
rc = sqlite3_step(pstmt);
返回值有两个需要注意的返回值
- SQLITE_DONE: 表示执行完毕
- SQLITE_ROW: 当使用select语句时,会得到多个数据,每次只能读取一行的值,
比如获取表中所有参数,需要多次使用sqlite3_step获取列。
const char *sql = "SELECT * FROM Cars;";
const char *pzTail;
rc = sqlite3_prepare_v2(db, sql, -1, &pStmt, &pzTail);
while(sqlite3_step(pStmt)==SQLITE_ROW){printf("id = %d\n", sqlite3_column_int(pStmt, 0));
}
7.4 sqlite3_column
上面的示例代码中使用了sqlite3_column,这是获取查询到的数据的函数
同样有三个,第二个参数是列号,从0开始。
int sqlite3_column_int(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
7.5 sqlite3_reset
将bind绑定的值全部取消清楚,方便重新绑定
int sqlite3_reset(sqlite3_stmt *pStmt);
这么做的目的就是在比如插入多个数据,绑定了一个人的数据,然后需要绑定第二个的时候需要清空statement。
8 读写blob型数据
读入
建表时定义一个blob,插入时用statement插入
const char *newSql = "INSERT INTO Images(Data) VALUES(?)";
rc = sqlite3_prepare_v2(db, newSql, -1, &pStmt, NULL);
sqlite3_bind_blob(pStmt, 1, &data, sizeof(data), NULL);
读取,也用statement读取,用column读取。
myData *pData = (myData*)sqlite3_column_blob(pStmt, 0);
下面是一个完整的读取写入代码。
#include <stdio.h>
#include "sqlite3.h"
#include <string.h>typedef struct
{int value1;double value2;
} myData;int main(void)
{sqlite3 *db = NULL;char *err_msg = NULL;int rc = sqlite3_open("../test.db", &db);if (rc != SQLITE_OK){fprintf(stderr, "Cannot open database: %s\n",sqlite3_errmsg(db));sqlite3_close(db);return 1;}const char *sql = "DROP TABLE IF EXISTS Images;""CREATE TABLE Images(Id INTEGER PRIMARY KEY, Data BLOB);";rc = sqlite3_exec(db, sql, NULL, NULL, &err_msg);if (rc != SQLITE_OK){fprintf(stderr, "Failed to select data\n");fprintf(stderr, "SQL error: %s", err_msg);sqlite3_free(err_msg);sqlite3_close(db);return 1;}sqlite3_stmt *pStmt = NULL;const char *newSql = "INSERT INTO Images(Data) VALUES(?)";rc = sqlite3_prepare_v2(db, newSql, -1, &pStmt, NULL);myData data = {100, 0.156};sqlite3_bind_blob(pStmt, 1, &data, sizeof(data), SQLITE_STATIC);rc = sqlite3_step(pStmt);if (rc != SQLITE_DONE){printf("execution failed: %s", sqlite3_errmsg(db));}sqlite3_finalize(pStmt);char *sql2 = "SELECT Data FROM Images WHERE Id = 1";pStmt = NULL;rc = sqlite3_prepare_v2(db, sql2, -1, &pStmt, NULL);if (rc != SQLITE_OK ) {fprintf(stderr, "Failed to prepare statement\n");fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));sqlite3_close(db);return 1;} rc = sqlite3_step(pStmt);int bytes = 0;if (rc == SQLITE_ROW){bytes = sqlite3_column_bytes(pStmt, 0);}myData *pData = (myData*)sqlite3_column_blob(pStmt, 0);printf("bytes: %d, %d, %lf\n", bytes, pData->value1, pData->value2);rc = sqlite3_finalize(pStmt); sqlite3_close(db);return 0;
}
参考
C语言操作SQLite3简明教程
深入理解SQLite3之sqlite3_exec及回调函数
玩转SQLite-11:C语言高效API之sqlite3_prepare系列函数
相关文章:

C语言与sqlite3入门
c语言与sqlite3入门 1 sqlite3数据类型2 sqlite3指令3 sqlite3的sql语法3.1 创建表create3.2 删除表drop3.3 插入数据insert into3.4 查询select from3.5 where子句3.6 修改数据update3.7 删除数据delete3.8 排序Order By3.9 分组GROUP BY3.10 约束 4 c语言执行sqlite34.1 下载…...
Rancher(v2.6.3)——安装Rancher
[详细安装说明请查看Rancher安装说明文档]:https://gitee.com/WilliamWangmy/snail-knowledge/blob/master/Rancher/Rancher%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3.md#1%E5%AE%89%E8%A3%85rancher Rancher部署Mysql(单机版):http…...
Aapche Nutch建立自己的搜索引擎
sudo apt install default-jdk‘ java -version openjdk version "11.0.22" 2024-01-16 vi .bashrc export JAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64 爬梯子下载源代码 Apache Nutch™ – Downloads mkdir -p urls cd urls touch seed.txt 里面放入我的网站…...

阅读笔记(ICIP2023)Rectangular-Output Image Stitching
“矩形输出”图像拼接 Zhou, H., Zhu, Y., Lv, X., Liu, Q., & Zhang, S. (2023, October). Rectangular-Output Image Stitching. In 2023 IEEE International Conference on Image Processing (ICIP) (pp. 2800-2804). IEEE. 0. 摘要 图像拼接的目的是将两幅视场重叠的…...

就业班 第二阶段 2401--3.26 day6 Shell初识 连接vscode
远程连接vs_code可能出现的问题 C:\Users\41703\.ssh 验证远程主机的身份,如果连不上vscode,可以尝试删除这里面的公钥代码。 重新安装那个扩展,排除扩展本身的问题 谁连过我,并操作了什么 curl https://gitea.beyourself.org.c…...

碳课堂|什么是碳资产?企业如何进行碳资产管理?
碳资产是绿色资产的重要类别,在全球气候变化日益严峻的背景下备受关注。在“双碳”目标下,碳资产管理是企业层面实现碳减排目标和低碳转型的关键。 一、什么是碳资产? 碳资产是以碳减排为基础的资产,是企业为了积极应对气候变化&…...

如何使用 ChatGPT 进行编码和编程
文章目录 一、初学者1.1 生成代码片段1.2 解释功能 二、自信的初学者2.1 修复错误2.2 完成部分代码 三、中级水平3.1 研究库3.2 改进旧代码 四、进阶水平4.1 比较示例代码4.2 编程语言之间的翻译 五、专业人士5.1 模拟 Linux 终端 总结 大多数程序员都知道,ChatGPT …...
学习java第二十四天
spring框架中有哪些不同类型的事件 Spring 提供了以下5种标准的事件: 上下文更新事件(ContextRefreshedEvent):在调用 ConfigurableApplicationContext 接口中的refresh方法时被触发。 上下文开始事件(ContextStart…...

中小型集群部署,Docker Swarm(集群)使用及部署应用介绍
1、Docker Swarm简介 说到集群,第一个想到的就是k8s,但docker官方也提供了集群和编排解决方案,它允许你将多个 Docker 主机连接在一起,形成一个“群集”(Swarm),并可以在这个 Swarm 上运行和管…...
gateway做负载均衡
在Spring Cloud中,Gateway可以通过配置文件来实现负载均衡。以下是一个简单的配置示例,它演示了如何将请求代理到名为service-instance的服务的两个不同实例。 spring:cloud:gateway:routes:- id: service-instance-routeuri: lb://service-instancepre…...
pytorch中的torch.hub.load()
pytorch提供了torch.hub.load()函数加载模型,该方法可以从网上直接下载模型或是从本地加载模型。官方文档 torch.hub.load(repo_or_dir, model, *args, sourcegithub, trust_repoNone, force_reloadFalse, verboseTrue, skip_validationFalse, **kwargs)参数说明&a…...

R语言学习——Rstudio软件
R语言免费但有点难上手,是数据挖掘的入门级别语言,拥有顶级的可视化功能。 优点: 1统计分析(可以实现各种分析方法)和计算(有很多函数) 2强大的绘图功能 3扩展包多,适合领域多 …...
触发器的工艺结构原理及选型参数总结
🏡《总目录》 目录 1,概述2,工作原理3,结构特点4,工艺流程4.1,掩膜制作4.2,晶片生长4.3,晶片切割4.4,晶片清洗4.5,掩膜光刻4.6,金属沉积5,选型参数5.1,触发类型5.2,触发频率...

Hana数据库 No columns were bound prior to calling SQLFetch or SQLFetchScroll
在php调用hana数据库的一个sql时报错了,查表结构的sql: select * from sys.table_columns where table_name VBAP SQLSTATE[SL009]: <<Unknown error>>: 0 [unixODBC][Driver Manager]No columns were bound prior to calling SQLFetch …...
DevOps是什么
DevOps 是一种将软件开发 (Dev) 和 IT运维 (Ops) 结合起来的实践、文化和哲学,旨在缩短系统开发生命周期,提供高质量的软件持续交付。它涉及多个关键实践和工具,其核心目的是加强开发和运维团队之间的协作和通信。以下是构成DevOps的一些重要…...

windows下的vscode + opencv4.8.0(C++) 配置
1.添加环境变量 D:\mingw64\bin 2.安装vscode 3.下载opencv 4.8.0 4.程序引用第三方库(opencv为例) 打开CMakeLists.txt,引入头文件,使用include_directories 加入头文件所在目录。静态链接库link_directories # 头文件 include_directories(D:/ope…...
微信小程序之多视频暂停播放,超出可视区域停止播放视频在自定义组件中实现案例
项目页面存在多个视频时,只播放视频可见范围内单个视频播放的解决方案 QQ录屏20240326175303 在自定义组件中无onPageScroll(e)监听页面滚动的函数所以在自定义组件中用<scroll-view>标签包裹所有组件(以下为WXML页面源码) <scroll…...
Java 加载外部 Jar 中的类并通过反射调用类中的方法
目录 问题 类加载器 获取外部 jar 包中的类以及方法 调用外部 jar 包中的方法 问题 工作中遇到一个需求,客户端将第三方的 jar 包上传到服务器中,系统需要解析出上传的 jar 中所有类以及类下的方法(方法名,方法输入参数类型&…...

Arduino+ESP8266+华为云物联网平台实现智能开关
前言 最近在做一个物联网项目,涉及到智能开关的开发。目前已经实现简单的TCP通信远程控制,但是考虑到后期的设备管理以及设备通信所需要的技术和服务器的维护成本,我决定将设备接入云平台。本文将详细阐述如何利用华为云的物联网平台&#x…...

使用 python 拆分 excel 文件
文章目录 1、安装虚拟环境(在特定文件夹内)2、脚本 split.sh3、运行脚本(在特定文件夹内)4、结果 1、安装虚拟环境(在特定文件夹内) brew install python3 xcode-select --install python3 -m venv my_pan…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...

AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...