🌈欢迎来到实战项目专栏 ~~ 从零实现AI大模型接入SDK
- 🌍博客主页 :张小姐的猫~江湖背景
- 🔥所属专栏 :C++项目 ~ AI大模型接入SDK
- 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏

AI大模型接入SDK

🌏持久化存储

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

ubuntu下SQLite命令行和开发库安装:
cpp
sudo apt install sqlite3 # 安装 sqlite3 命令⾏⼯具
sudo apt install libsqlite3-dev # 安装 sqlite 开发包
dpkg -L libsqlite3-dev # 列出已安装的 libsqlite3-dev 软件包所包含的所有⽂件及其安
装路径

编译时链接 sqlite3 库
cpp
makefile⽂件:
g++ main.cpp -o my_program -lsqlite3
CMakelists.txt:
target_link_libraries(${SDK_NAME} sqlite3)
🔥终端使用介绍
1️⃣常用命令
数据库操作命令:


SQLite支持列的亲和类型概念。任何列仍然可以存储任何类型的数据,当数据插入时,该字段的数据将会优先采用亲缘类型作为该值的存储方式。SQLite目前的版本支持以下五种亲缘类型:

在创建好表之后,sqlite会根据每个列的数据类型自动生成亲和类型
cpp
create table test{
a INT ---亲和类型:INTEGER
b TEXT ---亲和类型:TEXT
}
在插入数据的时候,sqlite会根据实际插入的数据,结合亲和类型来确定实际在磁盘上的存储类
c
insert into values("123",456)
- 对于a列
INT:实际插入的数据是"123"字符串,亲和类型是INTEGER,所以"123"字符串会被转化成整形数据123 - 对于b列
TEXT:实际插入的数据456整形数据,亲和类型为TEXT,456会被转化成字符串"456"
我们在定义数据表的时候,只需要知道这一列要存储什么类型的数据,把这个数据给好就行 ------ 不需要管存储类型与亲和类型(sqlite内部设置)
sqlite会根据偏好设置亲和类型,实际的存储类型取决于偏好类型转化规则
2️⃣使用演示
cpp
> sqlite3 # 打开 sqlite 命令⾏⼯具
.help # 查看帮助信息
.open student.db # 创建student数据库,数据库⽂件名称为student.db
.databases # 验证数据库。检查当前连接了哪些数据库,以及数据库的详细状态信息
.tables # 查看所有表
sqlite> CREATE TABLE student( #创建学⽣表
(x1...> stuid INTEGER PRIMARY KEY AUTOINCREMENT,
(x1...> name TEXT NOT NULL,
(x1...> age INTEGER,
(x1...> score REAL
(x1...> );
INSERT INTO students(name, age, score) VALUES # students中插⼊数据
...> ('张三', 18, 92.0),
...> ('李四', 19, 93.5),
...> ('王五', 18, 76.5);
select * from student; # 查看学⽣信息
1|张三|92.0
2|李四|100.0
3|卢本伟|99.1
DELETE FROM student WHERE score < 95; //删除小于95分的同学
select * from student;
2|李四|100.0
3|卢本伟|99.1
🔥常用api介绍
包含头文件 #include <sqlite3.h>
数据库连接管理:
cpp
int sqlite3_open(const char *filename, sqlite3 **ppDb);
功能 :打开一个数据库连接。如果数据库件不存在,则创建它
参数:filename - 数据库文件的路径ppDb:⼀个指向sqlite3*的指针。函数成功后会在这个指针里填入数据库连接句柄
返回值:SQLITE_OK 表示创建成功,否则为错误码
cpp
int sqlite3_close(sqlite3* db);
功能 :关闭打开的数据库连接,并释放所有资源
参数:要关闭的数据库连接句柄
返回值:SQLITE_OK表示成功,如果还有未完成的预处理语句
cpp
const char *sqlite3_errmsg(sqlite3* db);
功能 :获取与数据库连接相关的最后一次错误操作的英文描述字符串 。在操作失败后调用它来获取错误原因
参数 :db数据库连接句柄
返回值 :指向错误信息字符串的指针 。如果还有查询没有完成,将返回SQLITE_BUSY禁止关闭的错误消息
SQL语句预处理:
sqlite3_prepare_v2函数会对输入的SQL语句进行语法检测 ,如果语法有问题会立马返回错误码;如果语法正确,会将SQL编译成字节码 (给SQLite的虚拟机执行的形式)编译完成后,该函数会创建一个sqlite3_stmt 的结构,将编译的结构存储在该对象里
cpp
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,否则返回错误码
c
int sqlite3_bind_int64(sqlite3_stmt*, int index, sqlite3_int64 value);
功能 :向预处理语句中的指定参数位置绑定一个64位的整数值
参数:
index- 参数的序号,从1开始value- 要绑定的整数值
返回值:SQLITE_OK表示绑定成功,否则为错误码
cpp
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表示绑定成功,否则为错误码
执行语句
cpp
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:回调函数,每有⼀条结果记录就产生⼀次调用,可以设置为NULLarg:传递给回调函数的第一个参数errmsg:指向错误信息的指针。必须由用户自己sqlite3_free释放
返回值:执行成功返回SQLITE_OK,否则返回错误码
c
int sqlite3_step(sqlite3_stmt *pStmt);
功能 :用于逐步执行预处理语句。⼀般用于执行查询和更新操作,并返回执行结果。对于查询操作,sqlite3_step 需要多次调用,直到返回 SQLITE_DONE
参数 :pstmt - 预处理语句句柄
返回值:
SQLITE_ROW- 表示有一行结果数据就绪SQLITE_DONE- 表示语句执行完成- 否则表示有其他错误
c
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
功能:从当前结果行中,以const unsigned cht*的形式获取指定文本列的值
参数 :iCol表示列号,从0开始
返回值 :指向文本数据的指针
c
int sqlite3_finalize(sqlite3_stmt *pStmt);
功能:销毁预处理语句对象,释放所有关联资源
参数:pstmt - 要销毁的预处理语句句柄
返回值:成功返回SQLITE_OK,否则为错误码
🔥使用案例
下面持久化存储学生信息,学生基本信息包括学号、姓名、性别、年龄、学分
增删查改的实现思路如下:
-
写
SQL语句 -
对
SQL语句进行编译,生成一个预处理语句 -
绑定参数
-
执行SQL语句
-
最后清理
stmt指针
cpp
#include <cstddef>
#include <sqlite3.h>
#include <string>
#include <iostream>
struct StudentInfo {
std::string name;
std::string gender;
int age;
double gap;
};
class StudentDB{
public:
StudentDB(const std::string& db_name)
{
//创建并打开数据库
int rc = sqlite3_open(db_name.c_str(), &db);
if (rc != SQLITE_OK) {
std::cerr << "Failed to open database: " << sqlite3_errmsg(db) << std::endl;
sqlite3_close(db);
}
//初始化数据库表 ------ 创建学生信息表
if(!initDataBase()) {
sqlite3_close(db);
}
}
~StudentDB()
{
if (db != nullptr)
sqlite3_close(db);
}
//插入学生信息
bool insertStudent(const StudentInfo& studentInfo)
{
//VALUES 是一个占位符,表示将要插入的值
std::string insertSQL = R"(
INSERT INTO students (name, gender, age, gap)
VALUES (?, ?, ?, ?);
)";
//对SQL语句进行编译,生成一个预处理语句
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(db, insertSQL.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db) << std::endl;
return false;
}
// 绑定参数
sqlite3_bind_text(stmt, 1, studentInfo.name.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, studentInfo.gender.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 3, studentInfo.age);
sqlite3_bind_int64(stmt, 4, studentInfo.gap);
//执行SQL语句
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
std::cerr << "Failed to insert student: " << sqlite3_errmsg(db) << std::endl;
return false;
}
//清理
sqlite3_finalize(stmt);
return true;
}
//查询学生信息
bool queryStudent(const std::string& name)
{
std::string querySQL = R"(
SELECT * FROM students
WHERE name = ?;
)";
//准备SQL语句
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(db, querySQL.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db) << std::endl;
return false;
}
//绑定参数
sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);
//执行SQL语句
rc = sqlite3_step(stmt);
if (rc != SQLITE_ROW) {
std::cerr << "Failed to query student: " << sqlite3_errmsg(db) << std::endl;
return false;
}
//提取出结果
int stuid = sqlite3_column_int(stmt, 0);
std::string stuName = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1)); //sqlite3_column_text返回一个const unsigned char*,强转成const char*
std::string gender = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)); //sqlite3_column_text返回一个const unsigned char*,强转成const char*
int age = sqlite3_column_int(stmt, 3);
double gap = sqlite3_column_double(stmt, 4);
std::cout << "查询到的学生信息如下:" << std::endl;
std::cout << "Student ID: " << stuid << std::endl;
std::cout << "Name: " << stuName << std::endl;
std::cout << "Gender: " << gender << std::endl;
std::cout << "Age: " << age << std::endl;
std::cout << "Gap: " << gap << std::endl;
//清理
sqlite3_finalize(stmt);
return true;
}
bool queryAllStudents()
{
//查询所有学生信息
std::string querySQL = R"(
SELECT * FROM students;
)";
//准备SQL语句
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(db, querySQL.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db) << std::endl;
return false;
}
//不需要绑定参数 ------ 直接提取
std::cout << "--------------所有学生信息如下 ---------------" << std::endl;
while (sqlite3_step(stmt) == SQLITE_ROW) {
//提取出结果
int stuid = sqlite3_column_int(stmt, 0);
std::string name = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
std::string gender = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
int age = sqlite3_column_int(stmt, 3);
double gap = sqlite3_column_double(stmt, 4);
//输出结果
std::cout << "查询到的学生信息如下:" << std::endl;
std::cout << "Student ID: " << stuid <<
" Name: " << name <<
" Gender: " << gender <<
" Age: " << age <<
" Gap: " << gap << std::endl;
std::cout << "-----------------------------------------" << std::endl;
}
//检测是否还有数据
if (sqlite3_step(stmt) != SQLITE_DONE) {
std::cerr << "Failed to query all students: " << sqlite3_errmsg(db) << std::endl;
return false;
}
sqlite3_finalize(stmt);
return true;
}
//修改学生信息
bool updateStudent(const std::string& name, const StudentInfo& studentInfo)
{
std::string updateSQL = R"(
UPDATE students
SET name = ?, gender = ?, age = ?, gap = ?
WHERE name = ?;
)";
//准备SQL语句
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(db, updateSQL.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db) << std::endl;
return false;
}
//绑定参数
sqlite3_bind_text(stmt, 1, studentInfo.name.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, studentInfo.gender.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 3, studentInfo.age);
sqlite3_bind_int64(stmt, 4, studentInfo.gap);
sqlite3_bind_text(stmt, 5, name.c_str(), -1, SQLITE_TRANSIENT);
//执行SQL语句
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
std::cerr << "Failed to update student: " << sqlite3_errmsg(db) << std::endl;
return false;
}
//执行成功,清理stmt
sqlite3_finalize(stmt);
return true;
}
//删除学生信息
bool deleteStudent(const std::string& name)
{
std::string deleteSQL = R"(
DELETE FROM students
WHERE name = ?;
)";
//准备SQL语句
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(db, deleteSQL.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db) << std::endl;
return false;
}
//绑定参数
sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);
//执行SQL语句
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
std::cerr << "Failed to delete student: " << sqlite3_errmsg(db) << std::endl;
return false;
}
//清理
sqlite3_finalize(stmt);
return true;
}
private:
bool initDataBase()
{
const std::string createTableSQL = R"(
CREATE TABLE IF NOT EXISTS students (
stuid INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
gender TEXT,
age INTEGER,
gap REAL);
)";
int rc = sqlite3_exec(db, createTableSQL.c_str(), nullptr, nullptr, nullptr);
if (rc != SQLITE_OK) {
std::cerr << "Failed to create table: " << sqlite3_errmsg(db) << std::endl;
return false;
}
return true;
}
private:
sqlite3* db = nullptr;
};
int main()
{
return 0;
}
cpp
int main()
{
StudentInfo student1("张三", "男", 18, 4.5);
StudentInfo student2("李四", "女", 19, 3.5);
StudentInfo student3("王五", "男", 20, 2.5);
StudentInfo student4("赵六", "女", 21, 5.0);
StudentDB db("students.db");
db.insertStudent(student1);
db.insertStudent(student2);
db.insertStudent(student3);
db.insertStudent(student4);
//查询所有学生信息
db.queryAllStudents();
//修改学生张三的年龄和绩点
student1.age = 35;
student1.gap = 5.0;
db.updateStudent("张三", student1);
//查询指定学生信息
db.queryStudent(student1.name);
//删除学生
db.deleteStudent(student2.name);
db.queryAllStudents();
return 0;
}
接下来进行编译看看是否能实现?

📢写在最后
接下来登场的是 数据管理

