使用背景

最近在研究Wazuh的时候,发现服务端默认也使用了sqlite,原以为只有嵌入式使用,其实在这种本地化的软件中,使用sqlite也是一种很好的选择,至少软件的依赖性就少了很多,sqlite可以直接编译到产品中,不依赖mysql这种软件。

源码下载

访问《这里》可以下载sqlite3的源码。
源码就是4个文件

其中shell.c在不使用命令行的时候,无需编译进自己的产品。

构建环境

今天学了一个新的工程搭建方式,在开源软件上经常用到的CMake方式。

[root@localhost sqlite3]# tree
.
├── build
├── CMakeLists.txt
├── sqlite
│   ├── shell.c
│   ├── sqlite3.c
│   ├── sqlite3ext.h
│   └── sqlite3.h
└── src└── main.c3 directories, 6 files

CMakeLists.txt内容如下

cmake_minimum_required (VERSION 3.5)
project(demo)
include_directories (sqlite)add_executable(main ${PROJECT_SOURCE_DIR}/src/main.c ${PROJECT_SOURCE_DIR}/sqlite/sqlite3.c)
target_link_libraries (main pthread dl)add_executable(sqliteShell ${PROJECT_SOURCE_DIR}/sqlite/shell.c ${PROJECT_SOURCE_DIR}/sqlite/sqlite3.c)
target_link_libraries (sqliteShell pthread dl)

这个还挺有意思的,直接就能够根据后面几行,自动生成Makefile,并且编译出main和sqliteShell两个可执行程序。
看来以后要深入学习一下。

编译方式与运行

cd build
cmake .. && make
./main

main函数就简单的获取一个版本就可以进行测试了。

#include <stdio.h>
#include "sqlite3.h"int main(void)
{printf("%s\n", sqlite3_libversion());return 0;
}
[root@localhost sqlite3]# cd build/
[root@localhost build]# cmake ..
-- The C compiler identification is GNU 8.5.0
-- The CXX compiler identification is GNU 8.5.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/sqlite3/build
[root@localhost build]# make
[ 16%] Building C object CMakeFiles/main.dir/src/main.c.o
[ 33%] Building C object CMakeFiles/main.dir/sqlite/sqlite3.c.o
[ 50%] Linking C executable main
[ 50%] Built target main
[ 66%] Building C object CMakeFiles/sqliteShell.dir/sqlite/shell.c.o
[ 83%] Building C object CMakeFiles/sqliteShell.dir/sqlite/sqlite3.c.o
[100%] Linking C executable sqliteShell
[100%] Built target sqliteShell
[root@localhost build]# ./main
3.39.3

以上内容参考《C语言操作SQLite3简明教程》

C语言方式

这里主要学习一下sqlite3的一些API函数
可以参考文章《sqlite3接口API函数备注(2)》,下面介绍一些有意思的调用。

数据库打开

值得注意的是数据库的打开时候的参数,可以根据情况,例如多线程,进行选择。

SQLITE_API int sqlite3_open_v2(const char *filename,   /* Database filename (UTF-8) */sqlite3 **ppDb,         /* OUT: SQLite db handle */int flags,              /* Flags */const char *zVfs        /* Name of VFS module to use */
);

第一个参数为数据库文件名字,值得注意的点是:

  • 如果文件名为“:memory:”,则会为连接创建一个专用的临时内存数据库。数据库连接关闭时,内存中的数据库将消失。SQLite的未来版本可能会使用以“:”字符开头的其他特殊文件名。建议当数据库文件名实际上以“:”字符开头时,应在文件名前面加上路径名,如“/”以避免歧义。
  • 如果文件名为空字符串,则将创建一个专用的临时磁盘数据库。一旦数据库连接关闭,此专用数据库将自动删除。

第三个参数flags,含义如下

参数 含义 是否必选
SQLITE_OPEN_READONLY 只读模式,如果数据库不存在,会返回错误 Y
SQLITE_OPEN_READWRITE 读写模式,如果数据库不存在,会返回错误 Y
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE 读写方式打开。如果数据库不存在,会自动创建,sqlite3_open() and sqlite3_open16()函数就是这种模式 Y
SQLITE_OPEN_URI 如果设置了此标志,则文件名可以解释为URI N
SQLITE_OPEN_MEMORY 数据库将作为内存数据库打开。如果启用了共享缓存模式,则出于缓存共享的目的,数据库由“filename”参数命名,但在其他情况下忽略“filename” N
SQLITE_OPEN_NOMUTEX 新数据库连接将使用“多线程”[线程模式])这意味着允许单独的线程同时使用SQLite,只要每个线程使用不同的[数据库连接] N
SQLITE_OPEN_FULLMUTEX 新数据库连接将使用“序列化”[线程模式])这意味着多个线程可以安全地尝试同时使用相同的数据库连接。(互斥锁将阻止任何实际的并发,但在这种模式下,尝试不会有任何危害。) N
SQLITE_OPEN_SHAREDCACHE 数据库启用共享缓存,覆盖[sqlite3_enable_shared_cache()]提供的默认共享缓存设置。) N
SQLITE_OPEN_PRIVATECACHE 数据库禁用共享缓存,覆盖[sqlite3_enable_shared_cache()]提供的默认共享缓存设置。) N
SQLITE_OPEN_EXRESCODE 数据库连接在“扩展结果代码模式”下出现。换句话说,数据库行为具有如果[sqlite3_extended_result_codes(db,1)],其中在连接创建后立即调用数据库连接。除了设置扩展结果代码模式外,该标志还导致[sqlite3_open_v2()]返回扩展结果代码。 N
SQLITE_OPEN_NOFOLLOW 数据库名称不能是符号链接 N

部分内容翻译的很直白,见谅见谅

预编译下的增删改操作

这里主要讲一下数据库数据操作的预编译。

以前用数据库,就是老老实实每次都调用文本的sql语句,实际上每次都会进行语句的编译再执行,如果进行三次操作,就需要进行三次编译,那么我们可以将重复执行或者部分重复执行的sql语句,提前编译好,然后调用的时候,直接调用,就省去了一部分时间,提升了效率。

请看函数

// 准备语句
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 */
);
// 执行
int sqlite3_step(sqlite3_stmt*);
// 完成
int sqlite3_finalize(sqlite3_stmt *pStmt);

就是将zSql语句,编译成ppStmt,然后执行的时候就可以直接运行这个编译过的命令。
如果带有参数的话,需要通过下面的函数,进行参数设置

// 部分绑定函数接口
int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
// 语句重置
int sqlite3_reset(sqlite3_stmt *pStmt);

直接来一个创建数据库并且增删改查数据的例子吧。
代码较长,请多指教。

#include <stdio.h>
#include "sqlite3.h"int callback(void *NotUsed, int argc, char **argv, char **azColName)
{NotUsed = NULL;for (int i = 0; i < argc; ++i){printf("%s = %s\n", azColName[i], (argv[i] ? argv[i] : "NULL"));}printf("\n");return 0;
}int exec_sql(sqlite3 *db,char*   sqltxt)
{char *err_msg = NULL;int rc;printf("sqltxt:%s\n",sqltxt);rc = sqlite3_exec(db, sqltxt, callback, NULL, &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;}return 0;
}int main(void)
{sqlite3 *db = NULL;char *err_msg = NULL;int rc = 0;int i = 0;char text[50] = {0};const char *sql_init = "DROP TABLE IF EXISTS Testtable;" "CREATE TABLE Testtable(Id INT, Data TEXT);";const char *sql_insert = "insert into Testtable(Id,Data) values(?,?)";const char *sql_update = "update Testtable set Data = ? where Id = ?;";const char *sql_delete = "delete from Testtable where Id = ?;";const char *sql_search = "select * from Testtable";sqlite3_stmt *stmt_insert;sqlite3_stmt *stmt_update;sqlite3_stmt *stmt_delete;sqlite3_stmt *stmt_search;//打开数据库,不存在就创建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;}printf("Autocommit: %d\n", sqlite3_get_autocommit(db));//创建数据库和表rc = sqlite3_exec(db, sql_init, 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;}//查看数据printf("新建表\n");exec_sql(db,sql_search);// 插入三条数据rc = sqlite3_prepare_v2(db, sql_insert, -1, &stmt_insert, NULL);for (i = 0; i < 3; i++){sqlite3_bind_int(stmt_insert, 1, i);sprintf(text, "test%d", i);sqlite3_bind_text(stmt_insert, 2, text, -1, NULL);rc = sqlite3_step(stmt_insert);if (rc != SQLITE_DONE){printf("execution failed: %s\n", sqlite3_errmsg(db));}sqlite3_reset(stmt_insert);}sqlite3_finalize(stmt_insert);//查看数据printf("插入三条数据\n");exec_sql(db,sql_search);//修改第二条rc = sqlite3_prepare_v2(db, sql_update, -1, &stmt_update, NULL);sqlite3_bind_int(stmt_update, 2, 1);strcpy(text, "change");sqlite3_bind_text(stmt_update, 1, text, -1, NULL);rc = sqlite3_step(stmt_update);if (rc != SQLITE_DONE){printf("execution failed: %s\n", sqlite3_errmsg(db));}sqlite3_reset(stmt_update);//查看数据printf("修改第二条数据\n");exec_sql(db,sql_search);//删除第三条数据rc = sqlite3_prepare_v2(db, sql_delete, -1, &stmt_delete, NULL);sqlite3_bind_int(stmt_delete, 1, 2);rc = sqlite3_step(stmt_delete);if (rc != SQLITE_DONE){printf("execution failed: %s\n", sqlite3_errmsg(db));} sqlite3_reset(stmt_delete);printf("删除第三条数据\n");exec_sql(db,sql_search);sqlite3_close(db);return 0;
}

Blob数据类型存储

Bolb是二进制长对象的意思,通常用于存储大文件,通过二进制数据保存到数据库里,并可以从数据库里恢复指定文件。
常见的就是存储一些图片数据。

这里用存储并读取几个个结构体数据为例,内部涉及了读取多条数据结果的操作。

#include <stdio.h>
#include <stdint.h>
#include "sqlite3.h"typedef struct
{int64_t time;int32_t value;
} myData;int main(void)
{sqlite3 *db = NULL;char *err_msg = NULL;sqlite3_stmt *pStmt = NULL;int rc = 0;int i = 0;int bytes = 0;myData *pData = NULL;// 创建名为Images的表const char *sql_init = "DROP TABLE IF EXISTS Testtable;" "CREATE TABLE Testtable(Id INTEGER PRIMARY KEY, Data BLOB);";const char *sql_insert = "INSERT INTO Testtable(Data) VALUES(?)"; // 向Data列插入新值const char *sql_get = "SELECT Data FROM Testtable;";myData data = {10000, 200}; // 准备要写入的值rc = sqlite3_open("test.db", &db);if (rc != SQLITE_OK) {fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));return 1;}rc = sqlite3_exec(db, sql_init, NULL, NULL, &err_msg);if (rc != SQLITE_OK ) {fprintf(stderr, "Failed to select data\n");fprintf(stderr, "SQL error: %s\n", err_msg);goto exit;}rc = sqlite3_prepare_v2(db, sql_insert, -1, &pStmt, NULL);if (rc != SQLITE_OK) {fprintf(stderr, "Cannot prepare statement: %s\n", sqlite3_errmsg(db));goto exit;}sqlite3_bind_blob(pStmt, 1, &data, sizeof(data), SQLITE_STATIC); // 绑定需要写入的值for(i=0;i<5;i++){data.value=i;rc = sqlite3_step(pStmt);if (rc != SQLITE_DONE){printf("execution failed: %s", sqlite3_errmsg(db));goto exit;}}sqlite3_finalize(pStmt);    rc = sqlite3_prepare_v2(db, sql_get, -1, &pStmt, NULL);if (rc != SQLITE_OK ) {fprintf(stderr, "Failed to prepare statement\n");fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));goto exit;} rc = sqlite3_step(pStmt);while (rc == SQLITE_ROW){bytes = sqlite3_column_bytes(pStmt, 0);pData = (myData*)sqlite3_column_blob(pStmt, 0);printf("bytes: %d, %lld, %d\n", bytes, pData->time, pData->value);rc = sqlite3_step(pStmt);if(rc == SQLITE_DONE)break;}rc = sqlite3_finalize(pStmt);   exit:if(err_msg){sqlite3_free(err_msg);}if(db){sqlite3_close(db);}return 0;}

其他操作

SQLite也和mysql一样,支持命令行的操作,详细方式可以参考。
《一文掌握SQLite3基本用法》
《SQLite 教程》

结束语

好些天没写了,最近有点沉迷工作,荒废了学业。马上就周末了,更新一篇。

最近大家都在玩羊了个羊,大家都集中到了两个困惑上
1.怎么跳过第一关
2.怎么能过第二关
其实我就怀疑这个游戏的内容,全是随机的,根本没有考虑你这套组合,能不能完成,除非你看广告刷够了道具。

不过这也算是个成功的游戏,一个成功的吸引住你的游戏。至于能不能过关,他并不关心。咱们也不必苛责人家,毕竟都是程序员,赚的也不是用户的钱。

常见软件---SQLite3的C语言下使用相关推荐

  1. 学习环境配置:Manjaro、MSYS2以及常见软件

    0.前言 在说Manjaro之前,要先说一下Linux发行版.对于各大发行版而言,内核只有版本的差异,最重要的区别就是包管理系统.常见的包管理系统包括:Pacman,Apt , Yum和Portage ...

  2. Windows 小技巧10--Windows常见软件、系统配置

    Windows 小技巧10--Windows常见软件.系统配置 Windows是绝大多数人最常用的系统,因此有必要熟悉其常见的软件使用方法和系统配置.以下为笔者根据个人使用情况记录的一些常用操作,归类 ...

  3. matlab中的addemup是什么,毕业论文-rsa密码体制的设计及matlab语言下的实现

    四川理工学院毕业论文RSA密码体制的设计及MATLAB语言下的实现学生XXX学号06121020230专业数学与应用数学班级20062指导教师张金山四川理工学院理学院二O一O年六月摘要RSA算法是一个 ...

  4. 软件中级设计师 - 程序语言设计

    程序设计语言基本概述 程序设计语言是为了书写计算机程序而人为设计的符号语言,用于对计算过程进行 描述.组织和推导. 低级语言:机器语言(计算机硬件只能识别0和1的指令序列),汇编语言. 高级语言:功能 ...

  5. 软件设计师-JAVA程序设计语言

    Java语言简介: 背景 1991年 ,SUN MicroSystem公司的 Jame Gosling. Bill Joe等人 ,在电 视.控制烤面包箱等家用消费类电子产品上进行交互式操作的开发,开始 ...

  6. Ubuntu 20.04常见软件安装

    Ubuntu 20.04常见软件安装 安装系统 20.04 系统 制作启动盘后直接安装系统 具体安装可以参考Ubuntu 20.04安装指导 https://blog.csdn.net/weixin_ ...

  7. linux软件安装非系统盘,linux操作系统可不可以像安装windows软件一样在windows系统下的硬盘上安装...

    linux操作系统可不可以像安装windows软件一样在windows系统下的硬盘上安装 答案:2  信息版本:手机版 解决时间 2020-07-24 14:13 已解决 2020-07-23 16: ...

  8. HDL4SE:软件工程师学习Verilog语言(十一)

    11 流水线 前面一节介绍了状态机的概念.状态机用于描述事务处理的一个程序性流程,可以组成顺序,分支,循环的事务处理流程.这些概念本来在verilog中的行为级描述中是有的,但是由于不是RTL描述,因 ...

  9. 2021年度总结 | 葡萄城软件开发技术回顾(下)

    2021年度总结 | 葡萄城软件开发技术回顾(下) 在上节中,我们介绍了在过去一年中葡萄城在控件领域中的一些新探索,新尝试. (详细内容:https://www.cnblogs.com/powerto ...

最新文章

  1. ./configure: error: the HTTP rewrite module requires the PCRE library
  2. Django 中 cookie的使用
  3. 开启 JM 的 trace 功能
  4. 亚信安全发布《2022年网络安全发展趋势及十大威胁预测》
  5. ASP.NET 网站路径
  6. Linux虚拟化:KVM影子页表
  7. 2018-01-03 烂尾工程: Java实现的汇编语言编译器
  8. worldwind系列教程
  9. $.ajax+php实战教程之下拉时自动加载更多文章原理分析
  10. 第6课时 语音识别
  11. 《CSS世界》:一本CSS领域的内功心法修炼手册
  12. C/C++ Dev-cpp 5.4.0下载安装包,百度网盘
  13. 电力系统谐波分析代码
  14. 美国大学计算机科学与物理,美国大学物理专业浅谈
  15. Java实现随机验证码和验证码图片渲染功能
  16. thinkpad s5黑将摄像头最新驱动_第一款以iOS方式运行的安卓手机:联想新机S5黑科技震撼来袭!...
  17. HBuilderX 插件下载失败 解决
  18. 修改apk图标及名字
  19. idea去掉拼写检查
  20. facade 门面模式和mediator 调停者

热门文章

  1. 如何看一篇论文的基金支持项目和获奖研究项目?
  2. JavaScript原始数据类型
  3. 电子信息工程专业的发展方向(读此明志)
  4. Java工具类、异常和集合(温习知识点)
  5. 推荐开发人员看的较有影响力的书籍
  6. 360第三季营收21亿:净亏近16亿 财务负责人离职
  7. 麻了,都是科班出身的,学弟月薪却是我的3倍。
  8. SpringBoot实用开发
  9. 网络小说《赘婿》中涉及的地名及其地图
  10. 【免费思维导图软件】万彩脑图大师教程 | 导出导入思维导图模板