sqlite3的API以及命令行
sqlite是目前最流行的嵌入式数据库。
所谓嵌入式,就是足够简单,可以嵌入到我们自己开发的应用程序之中。
在Linux系统中,sqlite的使用只需要使用它的API,连接它的动态连接库,甚至都不用连接,sqlite的实现只使用一个C语言源程序,直接编译进自己的应用里面就好。
现在sqlite的最新版本是3,所以我们后面会以这个版本为例。
API
sqlite的API简单到什么程序呢?
当我们开发应用的时候,通常的情况下,只需要使用sqlite3_open、sqlite3_exec与sqlite3_close这三个函数就够了。
它们的原型为:
int sqlite3_open(const char *filename, sqlite3 **ppDb);int sqlite3_close(sqlite3*);int sqlite3_exec( sqlite3*, /* An open database */ const char *sql, /* SQL to be evaluated */ int (*callback)(void*,int,char**,char**), /* Callback function */ void *, /* 1st argument to callback */ char **errmsg /* Error msg written here */
);
这三个函数都使用了一个sqlite3的指针的指针,指向了我们要操作的数据库实体的指针,不用解释。
sqlite3_open的第一个参数,表示要创建的数据库的路径。
值得一提的是sqlite3_exec。它有一个回调函数以及参数,当有多个返回值的时候,比如select语句被执行之后,将通过callback函数把每一条记录返回。另外还有一个错误字符串,如果出错将被赋值,需要应用层释放。
如:
static int
get_id_callback (void *para, int n_column, char **column_value, char **column_name)
{ int *id = (int *)para; if (column_value[0] != NULL) { *id = strtoull (column_value[0], NULL, 10); } return 0;
}int main (char *argc, char *argv[])
{ gchar *dirname; sqlite3 *db;char *errMsg;int rc;if (sqlite3_open ("/tmp/test.sqlite", &db) != 0) { printf ("Open sqlite db failed: %s.", file, strerror (errno)); return 1; } rc = sqlite3_exec (db, "select * from media", get_id_callback, NULL, &errMsg); if (rc != SQLITE_OK) { printf ("SQL error: %s in [%s]", errMsg, text); sqlite3_free (errMsg); return 2;}sqlite3_close (db); return 0;
}
转义
sqlite3_exec执行的sql语句里面,如果有值字符串中含有’,需要进行转义。
转义的格式是使用两个’,即’'。
如:
const char *lan = "It's a secret !";
这里的lan需要转义为:
const char *lan = "It''s a secret !";
可以写一个简单的转化函数实现这个功能:
int convert_str(const char *str, char *output, size_t out_size)
{*p; int trans_len;for (trans_len = 0, p = str; *p && trans_len + 2 < out_size; trans_len++, p++) { output[trans_len] = *p; if (*p == '\'') { output[trans_len + 1] = *p; trans_len++; } }if (trans_len + 1 >= out_size) {printf("str is too long\n");return -1;}output[trans_len] = '\0';return trans_len;
}
除了这样转义,还有没有更好的方法呢?
有的。
方法就是使用预编译执行。
预编译执行
所谓预编译执行,就是生成一个sql语句的结构,再赋值进去,之后执行。
这样做有多个好处。
首先是字符串不用转义了。
其次是,生成的sql语句结构可以复用,每次重置,再赋值,可以极大地提升性能。
预编译执行的方法也很简单,就是三步:
- 使用
sqlite3_prepare生成一个sqlite3_stmt结构。 - 使用
sqlite3_bind绑定值。 - 使用
sqlite3_step执行。
sqlite3_prepare_v2
sqlite3_prepare_v2是建议的新版本,其实还有一个为了兼容性的sqlite3_prepare以及更新的sqlite3_prepare_v3。基于“性价比”考量,我们使用sqlite3_prepare_v2就行了。
sqlite3_prepare_v2的原型为:
SQLITE_API int sqlite3_prepare_v2( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
其中,db是我们打开的数据库实例,zSql是我们要执行的sql语句,语句中的变量使用?进行占位,而ppStmt是我们生成的sqlite3_stmt结构的指针的指针。
sqlite3_bind_*
为了绑定不同的值,有几个不同的函数可以使用,如:sqlite3_bind_int、sqlite3_bind_double、sqlite3_bind_text等。
SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, void(*)(void*));
SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
// 省略其它
这些函数都是第一个是前面生成的sqlite3_stmt的指针,第二个是绑定的值的位置,第三个以及后面是值信息。
值得注意的是,这些函数的位置参数,即索引,从1开始。
比如,我们使用了
sqlite3_bind_int (stmt, 1, 1024);
就是把生成stmt的sql中的第1个?赋值了,不要使用0。
sqlite3_step
赋值完成后,就使用sqlite3_step执行。
这个函数原型特别简单,就是:
SQLITE_API int sqlite3_step(sqlite3_stmt*);
但是这个函数的返回值很丰富。不同的返回值,需要做不同的处理。
比如,在不出错的情况下,如果返回SQLITE_DONE,表示执行成功。
如果返回SQLITE_ROW,表示返回了一行数据,我们可以使用sqlite_column_*族的函数取得列的值。之后需要再次调用sqlite3_step,直到最后返回了SQLITE_DONE。
sqlite3_column_*
SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
// 省略其它
可以看到,这些函数基本上跟sqlite3_bind_*是对应的。
唯一需要注意的是,这些函数的索引是从0开始的。
另外,sqlite3_data_count可以取得当前行的列数。
示例
最后来一个示例,总结一下:
int insert_medias(sqlite3_database *db, struct media *medias, size_t count)
{int ret;sqlite3_stmt *stmt;const char *sql = "INSERT INTO media(path, size) VALUES(?,?);";if (sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL) != SQLITE_OK) {printf ("sqlite3_prepare_v2() error: %s\n", sqlite3_errmsg (db));return -1;}for(int i = 0; i < count; i++){sqlite3_bind_text(stmt, 1, medias[i].name, strlen (medias[i].name), NULL);sqlite3_bind_int(pstmt, 2, medias[i].size);if (sqlite3_step(pstmt) != SQLITE_DONE) {printf ("sqlite3_step() error: %s\n", sqlite3_errmsg (db));return i;}sqlite3_reset(pstmt);}sqlite3_finalize(pstmt);return count;
}void query_media (sqlite3_database *db)
{int ret;sqlite3_stmt *stmt;const char *sql = "SELECT * FROM media;";if (sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL) != SQLITE_OK) {printf ("sqlite3_prepare_v2() error: %s\n", sqlite3_errmsg (db));return -1;}ret = sqlite3_step (stmt);while (ret == SQLITE_ROW) {printf("get media: %s, size: %d\n", sqlite3_coumn_text (stmt, 0), sqlite3_column_int (stmt, 1));ret = sqlite3_step (stmt);}if (ret != SQLITE_DONE) {printf ("sqlite3_step() error: %s\n", sqlite3_errmsg (db)); }
}
命令行
sqlite3有一个命令行工具,就叫sqlite3。
我们使用sqlite3 /tmp/test.sqlite3就可以打开前面创建的数据库。
在这个命令终端里,以.开头的是内置的命令。
如:
> .help 显示帮助
> .tables 显示数据表
> .schema TableName 显示创建数据表的语句,类似mysql里的describe
> .open 文件名 关闭当前,打开另一个数据库
> .quit 退出
> .save 文件名 另存当前数据库到文件
> .headers on/off 在查询结果前面,是否显示列名
执行sql语句,就直接输入,加;回车执行就行了。
相关文章:
sqlite3的API以及命令行
sqlite是目前最流行的嵌入式数据库。 所谓嵌入式,就是足够简单,可以嵌入到我们自己开发的应用程序之中。 在Linux系统中,sqlite的使用只需要使用它的API,连接它的动态连接库,甚至都不用连接,sqlite的实现…...
css button 点击效果
<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><title>button点击效果</title><style>#container {display: flex;align-items: center;justify-content: center;}.pushable {position: relat…...
表征流体作用力的参数及其特性
在圆柱绕流研究中,这些参数分别表征流体作用力的关键特性,以下是详细解析: 📊 参数物理意义及工程应用 符号名称物理意义典型值范围(参考)工程意义 C d m a x C_{dmax} Cdmax最大阻力系数瞬时阻力系数&a…...
Foundation Agent:深度赋能AI4DATA
2025年5月17日,第76期DataFunSummit:AI Agent技术与应用峰会将在DataFun线上社区举办。Manus的爆火并非偶然,随着基础模型效果不断的提升,Agent作为大模型的超级应用备受全世界的关注。为了推动其技术和应用,本次峰会计…...
Docker--Docker镜像原理
docker 是操作系统层的虚拟化,所以 docker 镜像的本质是在模拟操作系统。 联合文件系统(UnionFS) 联合文件系统(UnionFS) 是Docker镜像实现分层存储的核心技术,它通过将多个只读层(Image Laye…...
SpringAI+DeepSeek大模型应用开发——2 大模型应用开发架构
目录 2.大模型开发 2.1 模型部署 2.1.1 云服务-开放大模型API 2.1.2 本地部署 搜索模型 运行大模型 2.2 调用大模型 接口说明 提示词角色 编辑 会话记忆问题 2.3 大模型应用开发架构 2.3.1 技术架构 纯Prompt模式 FunctionCalling RAG检索增强 Fine-tuning …...
Transformer 架构 - 编码器 (Transformer Architecture - Encoder)
1.Transformer 编码器整体结构 Transformer 编码器的结构相对直观:它由 N 个完全相同的编码器层 (Encoder Layer) 堆叠而成。 图1: Transformer 编码器整体结构示意图 (简化) 输入序列(例如,通过 embedding 层转换后的词向量)首先会加上位置编码,然后传入第一个编码器层…...
2.2/Q2,Charls最新文章解读
文章题目:Association of uric acid to high-density lipoprotein cholesterol ratio with the presence or absence of hypertensive kidney function: results from the China Health and Retirement Longitudinal Study (CHARLS) DOI:10.1186/s12882-…...
下拉框select标签类型
在我们很多页面里有下拉框的选择,这种元素怎么定位呢?下拉框分为两种类型:我们分别针对这两种元素进行定位和操作 select标签 : 通过select类处理。 非select标签 1、针对下拉框元素,如果是Select标签类型,…...
CentOS 7 linux系统从无到有部署项目
环境部署操作手册 一、Maven安装与配置 1. 下载与解压 下载地址:https://maven.apache.org/download.cgi?spm5238cd80.38b417da.0.0.d54c32cbnOpQh2&filedownload.cgi上传并解压解压命令: tar -zxvf apache-maven-3.9.9-bin.tar.gz -C /usr/loc…...
李飞飞团队新作WorldScore:“世界生成”能力迎来统一评测,3D/4D/视频模型同台PK
从古老神话中对世界起源的幻想,到如今科学家们在实验室里对虚拟世界的构建,人类探索世界生成奥秘的脚步从未停歇。如今,随着人工智能和计算机图形学的深度融合,我们已站在一个全新的起点,能够以前所未有的精度和效率去…...
如何在米尔-STM32MP257开发板上部署环境监测系统
本文将介绍基于米尔电子MYD-LD25X开发板(米尔基于STM35MP257开发板)的环境监测系统方案测试。 摘自优秀创作者-lugl4313820 一、前言 环境监测是当前很多场景需要的项目,刚好我正在论坛参与的一个项目:Thingy:91X 蜂窝物联网原型…...
MySQL之SQL优化
目录 1.插入数据 2.大批量插入数据 3.order by优化 4.group by优化 5.limit优化 6.count优化 count用法 7.update优化 1.插入数据 如果我们需要一次性往数据库表中插入多条记录,可以从以下三个方面进行优化 第一个:批量插入数据 Insert into tb_test va…...
python_level1.2
目录 一、变量 例如:小正方形——>大正方形 【1】第一次使用这个变量,所以说:定义一个变量length; 【2】:是赋值符号,不是等于符号。(只有赋值,该变量才会被创建)…...
Linux、Kylin OS挂载磁盘,开机自动加载
0.实验环境: 1.确定挂载目录,如果没有使用mkdir 进行创建: mkdir /data 2.查看磁盘 lsblk #列出所有可用的块设备df -T #查看磁盘文件系统类型 3.格式化成xfs文件系统 (这里以xfs为例,ext4类似) mkfs.xfs /dev/vdb 4.挂载到…...
FPGA-VGA
目录 前言 一、VGA是什么? 二、物理接口 三、VGA显示原理 四、VGA时序标准 五、VGA显示参数 六、模块设计 七、波形图设计 八、彩条波形数据 前言 VGA的FPGA驱动 一、VGA是什么? VGA(Video Graphics Array)是IBM于1987年推出的…...
java的lambda和stream流操作
Lambda 表达式 ≈ 匿名函数 (Lambda接口)函数式接口:传入Lambda表达作为函数式接口的参数 函数式接口 只能有一个抽象方法的接口 Lambda 表达式必须赋值给一个函数式接口,比如 Java 8 自带的: 接口名 作用 Functio…...
【嵌入式】【阿里云服务器】【树莓派】学习守护进程编程、gdb调试原理和内网穿透信息
目录 一. 守护进程的含义及编程实现的主要过程 1.1守护进程 1.2编程实现的主要过程 二、在树莓派中通过三种方式创建守护进程 2.1nohup命令创建 2.2fork()函数创建 2.3daemon()函数创建 三、在阿里云中通过三种方式创建守护进程 3.1nohup命令创建 3.2fork()函数创建 …...
数据结构学习笔记 :树与二叉树详解
目录 树的基本概念二叉树的定义与特性二叉树的存储结构 3.1 顺序存储 3.2 链式存储二叉树遍历特殊二叉树类型总结与应用场景 一、树的基本概念 核心定义 树:由根节点和若干子树构成的层次结构。叶子节点(终端节点):没有子节点的…...
前沿篇|CAN XL 与 TSN 深度解读
引言 1. CAN XL 标准演进与设计目标 2. CAN XL 物理层与帧格式详解 3. 时间敏感网络 (TSN) 关键技术解析 4. CAN XL + TSN 在自动驾驶领域的典型应用...
七、LangChain Tool类参数对接机制解析:基于Pydantic的类型安全与流程实现
LangChain 的 Tool 类(包括 BaseTool 和 StructuredTool)通过 参数校验、输入解析、函数调用 的流程,将外部函数与 Agent 的逻辑对接。以下是其内部逻辑的详细解析: 1. 工具与函数对接的核心机制 (1) 工具的定义方式 LangChain 提供了两种主要方式定义工具: 继承 BaseTo…...
Spring-AI-alibaba 结构化输出
1、将模型响应转换为 ActorsFilms 对象实例: ActorsFilms package com.alibaba.cloud.ai.example.chat.openai.entity;import java.util.List;public record ActorsFilms(String actor, List<String> movies) { } GetMapping("/toBean")public Ac…...
AI大模型科普:从零开始理解AI的“超级大脑“,以及如何用好提示词?
大家好,小机又来分享AI了。 今天分享一些新奇的东西, 你有没有试过和ChatGPT聊天时,心里偷偷犯嘀咕:"这AI怎么跟真人一样对答如流?它真的会思考吗?" 或者刷到技术文章里满屏的"Token"…...
STM32单片机入门学习——第40节: [11-5] 硬件SPI读写W25Q64
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.18 STM32开发板学习——第一节: [1-1]课程简介第40节: [11-5] 硬件SPI读…...
【Java学习笔记】关键字汇总
Java 关键字汇总 用于定义数据类型的关键字: classinterfaceenumbyteshortintlongfloatdoublecharbooleanvoid 用于定义数据值的关键字: truefalsenull 用于定义流程控制的关键字: ifelseswitchcasedefaultwhiledoforbreakcontinueretu…...
langgraph框架之初识
1.什么是langgraph? LangGraph 是一个用于构建可控代理的底层编排框架。在AI中,代理也就是执行动作的智能体,也就是agent。使用这个框架可以构建一个可以自由控制的智能执行体,它可以帮我们做许多事情,如下࿱…...
如何将 .txt 文件转换成 .md 文件
一、因为有些软件上传文件的时候需要 .md 文件,首先在文件所在的目录中,点击“查看”,然后勾选上“文件扩展名”,这个时候该目录下的所有文件都会显示其文件类型了。 二、这时直接对目标的 .txt 文件进行重命名,把后缀…...
pdfjs库使用记录1
import React, { useEffect, useState, useRef } from react; import * as pdfjsLib from pdfjs-dist; // 设置 worker 路径 pdfjsLib.GlobalWorkerOptions.workerSrc /pdf.worker.min.js; const PDFViewer ({ url }) > { const [pdf, setPdf] useState(null); const […...
Qt 创建QWidget的界面库(DLL)
【1】新建一个qt库项目 【2】在项目目录图标上右击,选择Add New... 【3】选择模版:Qt->Qt设计师界面类,选择Widget,填写界面类的名称、.h .cpp .ui名称 【4】创建C调用接口(默认是创建C调用接口) #ifnd…...
Django REST framework 并结合 `mixin` 的示例
下面为你提供一个使用 Django REST framework 并结合 mixin 的示例,该示例将实现一个简单的图书管理 API。 项目需求 我们要创建一个图书管理系统的 API,支持对图书信息的创建、读取、更新和删除操作。 实现步骤 1. 项目初始化 首先,确保你已经安装了 Django 和 Django…...
