C++ 接入 SQLite 数据库:环境搭建、API 详解 与 两种执行方式对比

文章目录

  • 前言
  • [一、SQLite 介绍](#一、SQLite 介绍)
  • [二、ubuntu下SQLite命令行 和 开发库安装](#二、ubuntu下SQLite命令行 和 开发库安装)
  • 三、SQLite命令行工具的使用
    • [1. SQLite命令行工具下的操作命令](#1. SQLite命令行工具下的操作命令)
    • [2. 在SQLite命令行下执行操作命令 和 sql语句](#2. 在SQLite命令行下执行操作命令 和 sql语句)
  • [四、C++通过SQLite开发库 接入sqlite数据库](#四、C++通过SQLite开发库 接入sqlite数据库)
    • [1. SQLite库的常用api介绍](#1. SQLite库的常用api介绍)
    • [2. 实战演示](#2. 实战演示)
      • [2.1 sqlite3_exec 直接执行SQL语句](#2.1 sqlite3_exec 直接执行SQL语句)
      • [2.2 sqlite3_step 逐步执行预处理语句](#2.2 sqlite3_step 逐步执行预处理语句)

前言

SQLite库的头文件是: <sqlite3.h>


一、SQLite 介绍

SQLite官网: https://sqlite.org/draft/index.html

SQLite菜鸟教程: https://www.runoob.com/sqlite/sqlite-data-types.html

SQLite是⼀个开源、轻量级、零配置、无服务器、自包含、事务性、支持标准SQL、跨平台的数据库管理系统。

  • 开源: 免费使用,源码透明
  • 轻量级: 整个库非常小,编译之后仅需几百KB
  • 零配置: 无需安装、启动、停止 或 配置任何数据库服务器进程
  • 无服务器: SQLite没有独立的服务器进程,应用程序直接通过函数调用读写磁盘上的数据库文件
  • 自包含: 整个数据库就是⼀个独立的、跨平台的单个文件(通常是.db后缀),文件中包含所有表、索引、数据 和 元信息
  • 事务性: 完全支持ACID(原子性、一致性、隔离性、持久性)事务,即使系统崩溃 或 断电也能保证数据完整性
  • 支持标准SQL: 它使用SQL语句来管理和查询数据,最多支持128TB
  • 跨平台: 数据库文件跨平台
  • 简单易用: 只需包含一个 sqlite3.h 和一个库文件即可

一般常用于嵌入式系统、移动开发中。

二、ubuntu下SQLite命令行 和 开发库安装

  • 安装 sqlite3命令行工具 和 开发包的命令:
bash 复制代码
# 安装 sqlite3 命令⾏⼯具
sudo apt install sqlite3 
# 安装 sqlite 开发包
sudo apt install libsqlite3-dev 
  • 列出已安装的 libsqlite3-dev软件包所包含的所有文件及其安装路径:
bash 复制代码
dpkg -L libsqlite3-dev
bash 复制代码
ubuntu@VM-0-4-ubuntu:~$ dpkg -L libsqlite3-dev
/.
/usr
/usr/include
/usr/include/sqlite3.h                     # 核心头文件
/usr/include/sqlite3ext.h
/usr/lib
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/libsqlite3.a     # 核心静态库
/usr/lib/x86_64-linux-gnu/pkgconfig
/usr/lib/x86_64-linux-gnu/pkgconfig/sqlite3.pc
/usr/share
/usr/share/doc
/usr/share/doc/libsqlite3-dev
/usr/share/doc/libsqlite3-dev/copyright
/usr/lib/x86_64-linux-gnu/libsqlite3.so    # 核心动态库
/usr/share/doc/libsqlite3-dev/changelog.Debian.gz

三、SQLite命令行工具的使用

1. SQLite命令行工具下的操作命令

  • 进入SQLite命令行工具的命令:
bash 复制代码
sqlite3 
  • 数据库操作命令:
命令 说明 示例
.open 文件名 打开 或 创建数据库文件 .open student.db (student.db是数据库文件名)
.databases 显示当前连接的数据库 .databases
.attach 文件 as 别名 附加另⼀个数据库 .attach archive.db as archive
.backup 文件名 备份当前数据库 .backup backup.db
.restore 文件名 从备份恢复数据库 .restore recovery.db
.quit 退出SQLite命令行工具 .quit
.exit 退出SQLite命令行工具 .exit
.help 显示帮助信息 .help
  • 表的相关命令
命令 说明 示例
.tables 显示所有表 .tables
.schema [表名] 显示表结构 .schema students (students 是表名)
.indexes 表名 显示索引 .indexes students

注意:sqlite3支持 标准sql语句。

2. 在SQLite命令行下执行操作命令 和 sql语句

  • 使用sqlite3命令 进入SQLite命令行工具
  • 创建并进入数据库文件
  • 查看当前连接的数据库文件
  • 在数据库文件下创建 表格
  • 向表格插入数据 以及 查看表格中的所有数据
bash 复制代码
sqlite> INSERT INTO students(name, age, score) VALUES 
 ('张三', 18, 92.0),
 ('李四', 19, 93.5),
 ('王五', 18, 76.5);
sqlite> SELECT * FROM students;
1|张三|18|92.0
2|李四|19|93.5
3|王五|18|76.5
  • 删除成绩小于80分同学信息
bash 复制代码
sqlite> DELETE FROM students WHERE score < 80;
sqlite> SELECT * FROM students;
1|张三|18|92.0
2|李四|19|93.5

四、C++通过SQLite开发库 接入sqlite数据库

1. SQLite库的常用api介绍

使用SQLite库的api时,一定要包含头文件 <sqlite3.h>

  • 数据库连接管理:

(1)用数据库连接句柄 与 数据库文件进行连接

bash 复制代码
int sqlite3_open(const char *filename, sqlite3 **ppDb);

-功能:打开⼀个数据库连接。如果数据库文件不存在,则创建它
-参数:filename - 数据库⽂件的路径,
      ppDb:⼀个指向sqlite3*的指针。函数成功后会在这个指针里填入数据库连接句柄
-返回值:SQLITE_OK 表示创建成功,否则为错误码

(2)断开数据库连接句柄 与 数据库文件的连接,释放数据库连接句柄的空间

bash 复制代码
int sqlite3_close(sqlite3* db);

-功能:关闭打开的数据库连接,并释放所有资源
-参数:要关闭的数据库连接句柄
-返回值:SQLITE_OK 表示成功,如果还有未完成的预处理语句

(3)返回某个数据库连接 sqlite3 * db 最近一次错误的文本描述(在操作失败后调用它来获取错误原因)

bash 复制代码
const char *sqlite3_errmsg(sqlite3* db);

-功能:返回某个数据库连接 sqlite3* db 最近一次错误的文本描述(在操作失败后调用它来获取错误原因);
      方便用户在 sqlite3_prepare_v2 、sqlite3_step 、sqlite3_exec等 API调用失败时打印错误日志、定位原因
-参数:db数据库连接句柄
-返回值:只想错误信息字符串的指针。如果还有查询没有完成,将返回SQLITE_BUSY禁止关闭的错误消息

  • 执行SQL语句

(1) 直接执行SQL语句

bash 复制代码
int sqlite3_exec(sqlite3* db, const char *sql, int (*callback)(void*, int, char**, char**),
                 void *arg, char** errmsg);

-功能:执行一条 或 多条SQL语句,适合不返回数据的语句,如CREATE、INSERT
-参数:db: 数据库连接句柄
      sql: 要执⾏的SQL语句字符串
      callback: 回调函数指针,每有⼀条结果记录就产生去调用一次回调函数,可以设置为NULL
      arg: 传递给回调函数的第⼀个参数,可以设置为NULL
      errmsg: 指向错误信息的指针。必须⽤sqlite3_free释放
-返回值:执⾏成功返回SQLITE_OK,否则返回错误码

当 sqlite3_exec函数 执行多条SQL语句,返回多条结果记录时,第三个 和 第四个参数(callback 和 arg)才有用;
当 sqlite3_exec函数 只执行一条SQL语句时,可以将第三个 和 第四个参数(callback 和 arg)置为NULL

(2) 将SQL语句编译成⼀个预处理语句对象,绑定参数后,再执行

将⼀条SQL语句编译成⼀个预处理语句对象

bash 复制代码
int sqlite3_prepare_v2( sqlite3 *db, const char *zSql,int nByte,
                        sqlite3_stmt **ppStmt, const char **pzTail);
                        
-功能:将⼀条SQL语句编译成⼀个预处理语句对象,为绑定参数 和 执行做准备
-参数:db: 数据库连接句柄
      zSql: 要编译的SQL语句文本
      nByte: SQL文本的⻓度(字节),-1表示自动计算到\0结束
      ppStmt: 指向sqlite3_stmt*的指针,表示输出预处理结果语句的句柄
      pzTail: 指向未使用的SQL部分指针,通常置为NULL
-返回值:编译成功返回SQLITE_K,否则返回错误码

向预处理语句中的指定参数位置绑定参数 (参数的序号,从1开始)

bash 复制代码
int sqlite3_bind_int64(sqlite3_stmt*, int index, sqlite3_int64 value);

-功能:向预处理语句中的指定参数位置绑定⼀个64位的整数值
-参数:index - 参数的序号,从1开始
      value - 要绑定的整数值
-返回值:SQLITE_OK表⽰绑定成功,否则为错误码
bash 复制代码
int sqlite3_bind_text(sqlite3_stmt*, int index, const char *value, int len,
void(*destructor)(void*));

-功能:向预处理语句的指定参数位置绑定⼀个⽂本字符串
-参数: index - 参数的序号,从1开始
       value - 要绑定的⽂本字符串
       len - 字符串的⻓度(字节),-1表示自动计算到\0结束
       destructor - ⽤于指定SQLite不会尝试释放该字符串
                    SQLITE_STATIC:SQLite不会尝试释放该字符串
                    SQLITE_TRANSIENT:SQLite会制作该字符串的副本
-返回值:SQLITE_OK表⽰绑定成功,否则为错误码

用于逐步执行预处理语句。⼀般用于执行查询和更新操作,并返回执行结果。

bash 复制代码
int sqlite3_step(sqlite3_stmt *pStmt);
-功能:用于逐步执行预处理语句。⼀般用于执行查询和更新操作,并返回执行结果。
      对于查询操作,sqlite3_step 需要多次调用,直到返回 SQLITE_DONE
-参数:pstmt - 预处理语句句柄
-返回值:SQLITE_ROW - 表示有⼀行结果数据就绪
        SQLITE_DONE - 表示语句执行完成
        否则表示有其他错误

从结果行的指定位置提取参数值 (结果行的列号从0开始)

bash 复制代码
sqlite3_int64  sqlite3_column_int64(sqlite3_stmt*, int iCol);

-功能:从当前结果行中,以sqlite3_int64的形式获取指定文本列的值
-参数:iCol表⽰列号,从0开始
-返回值:以 sqlite3_int64 (通常就是 64 位整数)形式返回
bash 复制代码
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);

-功能:从当前结果行中,以const unsigned char*的形式获取指定文本列的值
-参数:iCol表⽰列号,从0开始
-返回值:指向⽂本数据的指针。

销毁预处理语句对象,释放所有关联资源

bash 复制代码
int sqlite3_finalize(sqlite3_stmt *pStmt);

-功能:销毁预处理语句对象,释放所有关联资源
-参数:pstmt - 要销毁的预处理语句句柄
-返回值:成功返回SQLITE_OK,否则为错误码

2. 实战演示

2.1 sqlite3_exec 直接执行SQL语句

使用SQLite库的api时,一定要包含头文件 <sqlite3.h>

数据库文件: /home/ubuntu/student.db

bash 复制代码
sqlite> create table students(
(x1...> id integer primary key autoincrement,
(x1...> name text not null,
(x1...> age integer,
(x1...> };
bash 复制代码
sqlite> select * from students;
1|张三|18
2|李四|19
3|王五|18
4|赵六|18
  • sqlite3_exec 直接执行SQL语句
cpp 复制代码
#include <sqlite3.h>

void create_table()
{
    sqlite3* _db;  // 数据库连接句柄
    // 将数据库连接句柄_db 与 数据库文件进行连接
    if(SQLITE_OK != sqlite3_open("/home/ubuntu/student.db", &_db))
    {
        // sqlite3_errmsg的作用:返回某个数据库连接 sqlite3* db 最近一次错误的文本描述
        // (在操作失败后调用它来获取错误原因)
        printf("打开数据库失败, db_name: %s\n", sqlite3_errmsg(_db))
    }
    printf("数据库初始化成功, db_name: %s\n", _db_path);)

    // 构建 SQL语句
    const std::string createSessionsTable = 
	      "CREATE TABLE IF NOT EXISTS students ("
	      "id integer primary key autoincrement, "
	      "name text not null, "
	      "age integer, "
	      ");";
	 char *errmsg = nullptr;
	 // sqlite3_exec 直接执行SQL语句
	 if(SQLITE_OK != sqlite3_exec(_db, createSessionsTable.c_str(), nullptr, nullptr, &errmsg))
	 {
	     printf("创建sessions表失败, errmsg: %s\n", errmsg);
	     sqlite3_free(errmsg);    // 必须⽤sqlite3_free释放错误信息的指针
	     errmsg = nullptr;
	     return false;
	 }
	 printf("创建sessions表成功\n");

     // 断开数据库连接句柄 与 数据库文件的连接,释放数据库连接句柄的空间
     sqlite3_close(_db);
}

2.2 sqlite3_step 逐步执行预处理语句

使用SQLite库的api时,一定要包含头文件 <sqlite3.h>

数据库文件: /home/ubuntu/student.db

bash 复制代码
sqlite> create table students(
(x1...> id integer primary key autoincrement,
(x1...> name text not null,
(x1...> age integer,
(x1...> };
bash 复制代码
sqlite> select * from students;
1|张三|18
2|李四|19
3|王五|18
4|赵六|18
  • sqlite3_step 执行预处理语句(插入命令,执行一次即可)
cpp 复制代码
#include <sqlite3.h>

void insert_text(int _id, string _name, int _age)
{
    sqlite3* _db;  // 数据库连接句柄
    // 将数据库连接句柄_db 与 数据库文件进行连接
    if(SQLITE_OK != sqlite3_open("/home/ubuntu/student.db", &_db))
    {
        // sqlite3_errmsg 获取与数据库连接相关的最后⼀次错误操作的英文描述字符串(获取错误原因)
        printf("打开数据库失败, db_name: %s\n", sqlite3_errmsg(_db))
    }
    printf("数据库初始化成功, db_name: %s\n", _db_path);

    // 构建 SQL语句
    const std::string sql ="INSERT INTO students (id, name, age) VALUES (?, ?, ?);";
    
    // 将 SQL语句sql 编译成⼀个预处理语句对象stmt, 为绑定参数 和 执行做准备
    sqlite3_stmt *stmt = nullptr;
    if(SQLITE_OK != sqlite3_prepare_v2(_db, sql.c_str(), -1, &stmt, nullptr))
    {
        printf("准备SQL语句失败, errmsg: %s\n", sqlite3_errmsg(_db));
        return false;
    }
    
    // 绑定参数
    sqlite3_bind_int64(stmt, 1, static_cast<int64_t>(_id));
    sqlite3_bind_text(stmt, 2, _name.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_int64(stmt, 3, static_cast<int64_t>(_age));
    
    // 执行预处理语句(插入命令只执行一次)
    if(SQLITE_DONE != sqlite3_step(stmt))
    {
        printf("执行SQL语句 (插入会话) 失败, errmsg: %s\n", sqlite3_errmsg(_db));
        sqlite3_finalize(stmt);
        return false;
    }
    
    sqlite3_finalize(stmt);  // 执行完成后, 释放stmt资源
    printf("执行SQL语句 (插入会话) 成功\n"); 
       
    // 断开数据库连接句柄 与 数据库文件的连接,释放数据库连接句柄的空间
    sqlite3_close(_db);
    return false;
}
  • sqlite3_step 逐步执行预处理语句(查询命令,一般执行多次)
cpp 复制代码
struct stud
{
private:
    int id;
    string name;
    int age;
};

std::vector<stud> insert_text(int _age)
{
    sqlite3* _db;  // 数据库连接句柄
    // 将数据库连接句柄_db 与 数据库文件进行连接
    if(SQLITE_OK != sqlite3_open("/home/ubuntu/student.db", &_db))
    {
        // sqlite3_errmsg 获取与数据库连接相关的最后⼀次错误操作的英文描述字符串(获取错误原因)
        printf("打开数据库失败, db_name: %s\n", sqlite3_errmsg(_db))
    }
    printf("数据库初始化成功, db_name: %s\n", _db_path);

    // 构建 SQL语句
    const std::string sql ="SELECT id, name, age FROM students WHERE age = ?;";
    
    // 将 SQL语句sql 编译成⼀个预处理语句对象stmt, 为绑定参数 和 执行做准备
    sqlite3_stmt *stmt = nullptr;
    if(SQLITE_OK != sqlite3_prepare_v2(_db, sql.c_str(), -1, &stmt, nullptr))
    {
        printf("准备SQL语句失败, errmsg: %s\n", sqlite3_errmsg(_db));
        return false;
    }
    
    // 绑定参数
    sqlite3_bind_int64(stmt, 1, static_cast<int64_t>(_age));
    
    std::vector<stud> vec_stu;
    // 执行预处理语句(查询命令一般执行多次,每次返回一行查询结果)
    // 比如:查询年龄 18岁的同学,一共有三位,查询一次返回一位同学的信息,一共要执行 3次查询
    while(SQLITE_ROW == sqlite3_step(stmt))
    {
        stud stu;
        stu.id = static_cast<int>(sqlite3_column_int64(stmt, 0));
        stu.name = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        stu.age = static_cast<int>(sqlite3_column_int64(stmt, 2));
        vec_stu.push_back(stu);
    }
    
    sqlite3_finalize(stmt);  // 执行完成后, 释放stmt资源
       
    // 断开数据库连接句柄 与 数据库文件的连接,释放数据库连接句柄的空间
    sqlite3_close(_db);
    return vec_stu;;
}

相关推荐
曹牧1 小时前
Oracle:CHR
数据库·oracle
TechWayfarer1 小时前
IP精准定位服务在保险行业的接入实践:区域需求洞察与精准服务
数据库·python·tcp/ip·flask
KKKlucifer1 小时前
数据分类分级产品排名解析:场景定制、规则联动、增量更新成核心能力
大数据·数据库·人工智能
minji...1 小时前
MySQL数据库 (七) MySQL表的基本查询(上),insert、replace、select、where、order by
数据库·mysql·select·replace·insert·order by·where
金融RPA机器人丨实在智能1 小时前
数据库运维Agent比价指南:国产自研产品适配国产数据库兼容性更好吗?
运维·数据库·人工智能·ai
IT策士1 小时前
Redis 从入门到精通:持久化RDB 与 AOF
数据库·redis·缓存
zh路西法2 小时前
基于yaml-cpp的C++参数服务器设计2:多级参数配置
linux·服务器·c++
啦啦啦啦啦zzzz2 小时前
算法总结(双指针)
c++·算法·双指针
gerrywhu2 小时前
【应用实践】PostGIS实现NDVI计算与植被覆盖分级统计分析-以武汉市2025年为例
数据库·postgis·栅格数据分析·st_mapalgebra·ndvi计算·植被覆盖分级统计·植被覆盖计算