当前位置: 首页 > news >正文

Linux下的c/c++开发之操作Sqlite3数据库

libsqlite3-dev 介绍(Linux 下的 SQLite3 C/C++ 开发包)

libsqlite3-dev 是一个开发包,在 Linux 环境下为使用 SQLite3 C API 进行开发的 C/C++ 程序员提供头文件(如 sqlite3.h)和静态库/动态库的链接信息(如 libsqlite3.so)。

它是 SQLite3 数据库的开发接口版本,不提供命令行工具,而是用于编译和构建程序时使用。

libsqlite3-dev 包含的内容:

类型路径描述
头文件/usr/include/sqlite3.h主头文件,声明所有 SQLite3 C API 函数,如 sqlite3_opensqlite3_execsqlite3_close
/usr/include/sqlite3ext.hSQLite3 插件扩展接口(用于实现用户自定义函数等)
动态库/usr/lib/x86_64-linux-gnu/libsqlite3.so动态链接库,编译时链接使用,运行时自动加载
静态库/usr/lib/x86_64-linux-gnu/libsqlite3.a静态链接库(可选,静态链接使用)
头文件路径/usr/include/所有头文件通常放在此处,包含时使用 <sqlite3.h>

libsqlite3-dev的安装

sudo apt update
sudo apt install libsqlite3-dev

安装成功后的简单示例:

test_sqlite3.cpp

#include <sqlite3.h>
#include <iostream>int main() {sqlite3* db = nullptr;int rc = sqlite3_open("test.db", &db);if(rc != SQLITE_OK) {std::cerr << "打开数据库失败: " << sqlite3_errmsg(db) << std::endl;if (db) {sqlite3_close(db);  // 即使打开失败也可能需要关闭 db}return 1;}std::cout << "SQLite3 数据库打开成功!" << std::endl;sqlite3_close(db);return 0;
}

编译:

gcc test_sqlite3.c -o test_sqlite3 -lsqlite3

正常情况下运行后输出:

SQLite3 数据库打开成功!

<sqlite3.h> 介绍

<sqlite3.h> 是 SQLite3 的主头文件,提供了完整的 SQLite3 C 接口函数集,你可以通过它来完成:

  • 打开或创建数据库文件(sqlite3_open

  • 执行 SQL(sqlite3_exec

  • 查询数据(sqlite3_prepare_v2 + sqlite3_step + sqlite3_column_xxx

  • 错误处理(sqlite3_errmsg

  • 事务管理(BEGIN, COMMIT, ROLLBACK

  • 内存管理、自定义函数、BLOB 操作等高级特性

它是你在 Linux 下用 C/C++ 访问 SQLite3 数据库的入口。

<sqlite3.h>中的结构体

常用结构体简介

结构体名类型作用描述使用场景举例
sqlite3数据库连接对象表示与 SQLite 数据库的连接,所有操作都依赖它sqlite3_open, sqlite3_close 用于打开和关闭数据库
sqlite3_stmt预处理语句句柄表示一条 SQL 语句的预编译句柄(如 SELECT、INSERT、UPDATE)sqlite3_prepare_v2, sqlite3_step 用于执行预处理语句
sqlite3_value列值表示 SQLite 查询结果中的单一列数据的类型(可以是整数、文本、BLOB、NULL)使用 sqlite3_column_* 函数从查询结果中提取数据
sqlite3_row行数据表示数据库查询结果中的一行数据,存储在一个 sqlite3_value 结构体中遍历查询结果时,使用 sqlite3_column_* 获取每一列
sqlite3_vfs虚拟文件系统用于管理 SQLite 的文件 I/O 操作,定义 SQLite 如何读写数据文件可用于自定义虚拟文件系统或定制文件 I/O
sqlite3_context执行上下文用于执行回调时保存状态的结构体,通常在用户定义的函数中使用在自定义 SQLite 函数时使用,保存用户的上下文数据

 sqlite3

sqlite3 结构体是 SQLite 数据库的主要句柄,表示一个数据库连接,管理数据库的生命周期和执行查询的操作。

typedef struct sqlite3 sqlite3;

示例:

sqlite3 *db;
int rc = sqlite3_open("test.db", &db);
if (rc) {fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
} else {printf("Opened database successfully\n");
}

sqlite3_value

sqlite3_value 结构体表示 SQLite 中的一个值(例如列值、函数参数)。它包含了该值的类型和实际的数据。

typedef struct sqlite3_value sqlite3_value;

示例:

sqlite3_value *value;
value = sqlite3_column_value(stmt, 0);
if (sqlite3_value_type(value) == SQLITE_INTEGER) {printf("Value is integer: %lld\n", sqlite3_value_int64(value));
}

sqlite3_row

sqlite3_row 结构体表示查询结果中的一行数据。SQLite 使用它来存储查询返回的每一行的字段数据。

typedef struct sqlite3_row sqlite3_row;

示例:

sqlite3_row *row;
while ((row = sqlite3_fetch_row(stmt)) != NULL) {const char *name = sqlite3_column_text(row, 0);int age = sqlite3_column_int(row, 1);printf("Name: %s, Age: %d\n", name, age);
}

sqlite3_stmt

sqlite3_stmt 结构体表示一个预处理语句。它包含了 SQL 查询的编译结果,并提供了执行该查询的接口。

typedef struct sqlite3_stmt sqlite3_stmt;

示例:

sqlite3_stmt *stmt;
const char *sql = "SELECT id, name FROM users WHERE age > ?";
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);

<sqlite3.h>中常用的方法

1. 初始化与连接管理

sqlite3_open

用于打开一个 SQLite 数据库连接(若数据库文件不存在则尝试创建),是使用 SQLite 的入口函数之一。

int sqlite3_open(const char *filename, sqlite3 **ppDb);

参数:

  • filename:数据库文件名。如果传入 ":memory:",则创建一个内存数据库;如果传入 "",创建一个临时数据库。

  • ppDb:传入一个 sqlite3 指针的地址,成功后返回已打开的数据库连接指针。

返回值:

  • 成功:返回 SQLITE_OK

  • 失败:返回其他错误码,例如 SQLITE_CANTOPEN。错误信息可通过 sqlite3_errmsg() 获取。

 

sqlite3_open_v2

sqlite3_open 的增强版本,支持更多控制选项(如只读、创建标志、自定义虚拟文件系统等)。

int sqlite3_open_v2(const char *filename,sqlite3 **ppDb,int flags,const char *zVfs
);

参数:

  • filename:数据库文件路径,规则同 sqlite3_open

  • ppDb:传出参数,返回数据库连接句柄。

  • flags:控制数据库打开行为。常用值包括:

    • SQLITE_OPEN_READONLY:只读模式打开。

    • SQLITE_OPEN_READWRITE:可读写(数据库必须存在)。

    • SQLITE_OPEN_CREATE:如果不存在则创建数据库。

    • 可组合使用,如 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE

  • zVfs:VFS 模块名称,传 NULL 使用默认模块。

返回值:

int sqlite3_close(sqlite3*);
  • 成功:返回 SQLITE_OK

  • 失败:返回错误码,例如 SQLITE_CANTOPENSQLITE_NOTADB 等。

sqlite3_close

关闭一个已经打开的 SQLite 数据库连接,并释放相关资源。此函数要求数据库中没有未完成的语句句柄(sqlite3_stmt)或未释放的内存,否则关闭会失败。

int sqlite3_close(sqlite3*);

参数:

  • sqlite3*:由 sqlite3_opensqlite3_open_v2 打开的数据库连接句柄。

返回值:

  • 成功:返回 SQLITE_OK

  • 失败:返回 SQLITE_BUSY(表示还有未释放的资源,如未 finalize 的语句)。

sqlite3_close_v2

sqlite3_close 类似,也是关闭数据库连接。但它允许有未清理的语句存在,数据库会被标记为“延迟关闭”,直到最后一个资源被释放后自动关闭。

int sqlite3_close_v2(sqlite3*);

sqlite3_errmsg

返回最近一次 SQLite 操作失败的错误信息(字符串形式),用于调试和日志记录。

const char *sqlite3_errmsg(sqlite3*);

参数:

  • sqlite3*:数据库连接句柄。

返回值:

  • 返回一个字符串,表示上一次出错时的详细错误信息。这个字符串是由 SQLite 管理的,不需要手动释放。

注意事项:

  • 如果是线程安全模式,不要跨线程使用该字符串。

  • 错误信息只对上一次失败的调用有效,之后任何成功调用都会覆盖它。

sqlite3_errcode

返回最近一次数据库操作的错误代码(整数形式),用于程序内判断错误类型。

int sqlite3_errcode(sqlite3*);

参数:

  • sqlite3*:数据库连接句柄。

返回值:

  • 返回错误代码,如:

    • SQLITE_OK:无错误。

    • SQLITE_BUSY:资源忙。

    • SQLITE_ERROR:SQL 错误或数据库缺陷。

    • SQLITE_IOERR:磁盘 I/O 错误。

    • SQLITE_NOMEM:内存不足。

    • 等等,详见官方文档错误码列表。

sqlite3_extended_errcode

返回更详细的错误码,错误信息比 sqlite3_errcode 更细致,例如区分不同类型的 SQLITE_IOERR_*

int sqlite3_extended_errcode(sqlite3*);

参数:

  • sqlite3*:数据库连接句柄。

返回值:

  • 返回扩展错误代码,例如:

    • SQLITE_IOERR_READ

    • SQLITE_IOERR_WRITE

    • SQLITE_CONSTRAINT_UNIQUE

示例:

#include <sqlite3.h>
#include <iostream>void open_with_sqlite3_open(const char* filename) {sqlite3* db = nullptr;std::cout << "[sqlite3_open] 尝试打开数据库: " << filename << "\n";int rc = sqlite3_open(filename, &db);if (rc != SQLITE_OK) {std::cerr << "打开失败\n";std::cerr << "  错误码: " << sqlite3_errcode(db) << "\n";std::cerr << "  扩展错误码: " << sqlite3_extended_errcode(db) << "\n";std::cerr << "  错误信息: " << sqlite3_errmsg(db) << "\n";} else {std::cout << "打开成功\n";}if (db) {sqlite3_close(db);std::cout << "[sqlite3_close] 已关闭数据库连接\n";}
}void open_with_sqlite3_open_v2(const char* filename) {sqlite3* db = nullptr;std::cout << "[sqlite3_open_v2] 尝试以读写模式打开数据库: " << filename << "\n";int rc = sqlite3_open_v2(filename,&db,SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,nullptr // 使用默认 VFS);if (rc != SQLITE_OK) {std::cerr << "打开失败\n";std::cerr << "  错误码: " << sqlite3_errcode(db) << "\n";std::cerr << "  扩展错误码: " << sqlite3_extended_errcode(db) << "\n";std::cerr << "  错误信息: " << sqlite3_errmsg(db) << "\n";} else {std::cout << "打开成功\n";}if (db) {sqlite3_close_v2(db);std::cout << "[sqlite3_close_v2] 已关闭数据库连接(异步可安全延后)\n";}
}int main() {std::cout << "===== 使用 sqlite3_open =====\n";open_with_sqlite3_open("example_open.db");std::cout << "\n===== 使用 sqlite3_open_v2 =====\n";open_with_sqlite3_open_v2("example_open_v2.db");return 0;
}

2. 执行 SQL(直接执行)

sqlite3_exec

sqlite3_exec() 是 SQLite 提供的一个简化接口,用于直接执行一条或多条 SQL 语句。适合执行不需要处理结果集的语句,如 CREATE TABLEINSERTUPDATEDELETE 等。

sqlite3_exec() 的执行过程中,我们可以通过回调函数来处理查询结果,sqlite3_exec() 直接返回所有结果并逐行传递给回调函数。

int sqlite3_exec(sqlite3 *db,                // 数据库连接句柄const char *sql,            // SQL 语句int (*callback)(void*,int,char**,char**), // 回调函数(可为 NULL)void *arg,                  // 传给回调函数的参数(可为 NULL)char **errmsg               // 出错信息(执行失败时会分配内存)
);

参数

  • db:打开的数据库连接句柄(由 sqlite3_open() 获得)。

  • sql:要执行的一条或多条 SQL 语句,语句之间用分号分隔。

  • callback:每当 SQL 查询返回一行结果时调用的函数。如果没有回调函数,可以传 NULL

  • arg:传递给回调函数的上下文数据,可以是任何自定义的数据。可以传 NULL

  • errmsg:如果非 NULL,执行失败时将设置指向错误信息字符串的指针。调用者需要在完成后调用 sqlite3_free() 释放此内存。

返回值

  • SQLITE_OK:表示执行成功。

  • 其他错误码:执行失败,具体错误信息可以通过 errmsg 获得。


示例:

#include <sqlite3.h>
#include <iostream>int callback(void* NotUsed, int argc, char** argv, char** azColName) {for (int i = 0; i < argc; i++) {std::cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL") << "\n";}std::cout << "------\n";return 0;
}int main() {sqlite3* db = nullptr;char* errMsg = nullptr;// 打开数据库if (sqlite3_open("test_exec.db", &db) != SQLITE_OK) {std::cerr << "无法打开数据库: " << sqlite3_errmsg(db) << "\n";return 1;}// 创建表并插入数据const char* sql = "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT);""INSERT INTO users(name) VALUES('Alice');""INSERT INTO users(name) VALUES('Bob');""SELECT * FROM users;";if (sqlite3_exec(db, sql, callback, nullptr, &errMsg) != SQLITE_OK) {std::cerr << "SQL 执行错误: " << errMsg << "\n";sqlite3_free(errMsg); // 释放错误信息}// 关闭数据库sqlite3_close(db);return 0;
}

3. 预处理语句与结果集处理

SQLite 不像 MySQL 那样返回一个“结果集对象(MYSQL_RES)”,它通过“预处理语句对象”sqlite3_stmt* 来遍历每一行返回结果。以下是预处理语句和处理查询结果时的主要函数。

sqlite3_prepare_v2

将 SQL 语句编译成可执行的预处理语句。

int sqlite3_prepare_v2(sqlite3 *db,              // 数据库连接句柄const char *sql,          // 要编译的 SQL 语句int nByte,                // SQL 语句的长度,如果是字符串以外的字符,可以传 -1sqlite3_stmt **ppStmt,    // 输出的 sqlite3_stmt 句柄const char **pzTail       // 指向 SQL 语句中未被解析的部分,通常可以为 NULL
);

参数:

  • db:数据库连接句柄。

  • sql:待编译的 SQL 语句。

  • nByte:SQL 语句的长度,若是字符串,传 -1。

  • ppStmt:返回预处理语句的 sqlite3_stmt 句柄。

  • pzTail:指向 SQL 语句未解析部分的指针,通常可以为 NULL

返回值:

  • SQLITE_OK:表示成功。

  • 其他错误码:表示失败。

sqlite3_bind_* 系列函数

sqlite3_bind_* 系列函数用于将动态的值绑定到 SQL 语句中的占位符参数,以便执行时能够传递实际数据。

常用函数

  • sqlite3_bind_int:绑定整数参数。

  • sqlite3_bind_text:绑定文本参数。

  • sqlite3_bind_double:绑定浮动参数。

  • sqlite3_bind_blob:绑定二进制数据。

  • sqlite3_bind_null:绑定 NULL 值。

int sqlite3_bind_int(sqlite3_stmt *pStmt, int iParam, int value);
int sqlite3_bind_text(sqlite3_stmt *pStmt, int iParam, const char *value, int n, void (*destructor)(void*));
int sqlite3_bind_double(sqlite3_stmt *pStmt, int iParam, double value);
int sqlite3_bind_blob(sqlite3_stmt *pStmt, int iParam, const void *value, int n, void (*destructor)(void*));
int sqlite3_bind_null(sqlite3_stmt *pStmt, int iParam);
  • 参数

    • pStmt:预处理语句句柄。

    • iParam:参数的索引,从 1 开始。

    • value:要绑定的值。

    • n:值的字节数,适用于文本、二进制数据。

    • destructor:用于清理 value 的回调函数,通常用于 TEXTBLOB 数据类型。

  • 返回值

    • SQLITE_OK:表示成功。

    • 其他错误码:表示失败。

sqlite3_clear_bindings

用于清除通过 sqlite3_bind_* 系列函数绑定到 SQL 语句中的所有参数值,但不会重置语句的编译状态(即不会清除结果或重置游标)。适用于想重用已准备好的 SQL 语句但重新绑定新参数的场景。

int sqlite3_clear_bindings(sqlite3_stmt *pStmt);

参数:

  • pStmt:已准备好的 SQL 语句对象(sqlite3_prepare_v2 的输出)。

返回值:

  • 返回 SQLITE_OK 表示绑定清除成功。

  • 传入非法的 pStmt 时可能返回其他错误码。

sqlite3_reset

用于重置一个已执行的预处理语句(sqlite3_stmt*),将其状态清空,以便再次绑定参数并重新执行。该函数不会清除绑定的参数值(除非配合 sqlite3_clear_bindings() 使用),而是将语句返回到 sqlite3_step() 执行前的初始状态。

int sqlite3_reset(sqlite3_stmt *pStmt);

参数:

  • pStmt:类型为 sqlite3_stmt*,表示需要被重置的预处理语句句柄。这个句柄通常是通过 sqlite3_prepare_v2() 创建的。

返回值:

  • 返回 SQLITE_OK 表示重置成功,语句已回到初始状态,下一次可以重新绑定参数并执行。

  • 如果返回的是非 SQLITE_OK 的其他错误码,则是该语句上一次执行 sqlite3_step() 时的返回码,这通常可用于调试或进一步的错误处理。

sqlite3_step

执行预处理语句并处理每一行的结果。

int sqlite3_step(sqlite3_stmt *pStmt);

参数:

  • pStmt:预处理语句句柄,由 sqlite3_prepare_v2 返回。

返回值:

  • SQLITE_ROW:有一行数据可返回。

  • SQLITE_DONE:查询完成,所有行已处理完。

  • 其他错误码:表示执行过程中出错。

每次调用 sqlite3_step,都会推进 sqlite3_stmt 句柄至下一行数据。每当 sqlite3_step 返回 SQLITE_ROW 时,表示当前行的查询结果可以通过 sqlite3_column_* 系列函数获取。

sqlite3_column_* 系列函数

从当前行的结果中提取列的数据。

常用函数

  • sqlite3_column_text:返回文本类型的列数据。

  • sqlite3_column_int:返回整数类型的列数据。

  • sqlite3_column_double:返回浮动类型的列数据。

  • sqlite3_column_blob:返回二进制数据。

  • sqlite3_column_bytes:返回列数据的字节数。

const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int col);
int sqlite3_column_int(sqlite3_stmt *pStmt, int col);
double sqlite3_column_double(sqlite3_stmt *pStmt, int col);
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int col);
int sqlite3_column_bytes(sqlite3_stmt *pStmt, int col);
  • 参数

    • pStmt:预处理语句句柄。

    • col:列的索引,从 0 开始。

  • 返回值

    • 对应的列数据,如文本、整数、浮动等。

sqlite3_finalize

释放预处理语句占用的资源。

int sqlite3_finalize(sqlite3_stmt *pStmt);
  • 参数

    • pStmt:预处理语句句柄。

  • 返回值

    • SQLITE_OK:表示成功。

    • 其他错误码:表示失败。

使用 sqlite3_finalize 清理 sqlite3_stmt 占用的资源。即使查询执行成功,释放预处理语句也是必要的步骤。

示例:

#include <sqlite3.h>
#include <iostream>int main() {sqlite3 *db;sqlite3_stmt *stmt;// 打开数据库if (sqlite3_open("test.db", &db) != SQLITE_OK) {std::cerr << "无法打开数据库: " << sqlite3_errmsg(db) << "\n";return 1;}// 编译 SQL 语句const char *sql = "SELECT id, name FROM users WHERE age > ?";if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {std::cerr << "无法编译 SQL: " << sqlite3_errmsg(db) << "\n";sqlite3_close(db);return 1;}// 第一次绑定参数并执行查询sqlite3_bind_int(stmt, 1, 30);  // 绑定 age > 30std::cout << "查询 age > 30 的用户:\n";while (sqlite3_step(stmt) == SQLITE_ROW) {int id = sqlite3_column_int(stmt, 0);const unsigned char *name = sqlite3_column_text(stmt, 1);std::cout << "ID: " << id << ", Name: " << name << std::endl;}// 清除绑定参数并重置语句sqlite3_clear_bindings(stmt);  // 清除参数绑定sqlite3_reset(stmt);           // 重置语句状态,准备再次执行// 第二次绑定新参数并再次查询sqlite3_bind_int(stmt, 1, 20);  // 绑定 age > 20std::cout << "\n查询 age > 20 的用户:\n";while (sqlite3_step(stmt) == SQLITE_ROW) {int id = sqlite3_column_int(stmt, 0);const unsigned char *name = sqlite3_column_text(stmt, 1);std::cout << "ID: " << id << ", Name: " << name << std::endl;}// 清理资源sqlite3_finalize(stmt);sqlite3_close(db);return 0;
}

4.状态信息获取

sqlite3_db_filename

该函数用于获取当前数据库连接所关联的数据库文件名。这对于调试、日志记录或者获取数据库文件路径非常有用。

const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);

参数

  • db:SQLite 数据库连接句柄。

  • zDbName:数据库名称。如果是主数据库,使用 "main";如果是附加数据库,使用附加数据库的名称。

返回值

  • 返回指定数据库(如主数据库或附加数据库)对应的文件名(路径)。如果出错,则返回 NULL

示例:


const char *filename = sqlite3_db_filename(db, "main");
if (filename) {std::cout << "主数据库文件路径: " << filename << "\n";
} else {std::cerr << "获取文件名失败\n";
}
sqlite3_db_status

该函数用于获取有关数据库的状态信息,如内存使用情况、锁状态、缓存大小等。它为用户提供了一个接口来监控数据库的性能和资源使用。

int sqlite3_db_status(sqlite3 *db,        // 数据库连接句柄int op,             // 状态信息的类型(如内存使用,锁状态等)int *pCur,          // 当前状态值int *pHiwater,      // 高水位值int reset           // 是否重置状态
);

参数

  • db:SQLite 数据库连接句柄。

  • op:要查询的状态类型。常见的状态类型有:

    • SQLITE_DBSTATUS_LOOKASIDE_HIT:查看缓存命中的次数。

    • SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:查看缓存未命中的大小。

    • SQLITE_DBSTATUS_CACHE_USED:查看缓存当前使用的字节数。

    • SQLITE_DBSTATUS_MEMORY_USED:查看当前内存使用量。

    • 还有其他类型的状态查询,详细请参考 SQLite 官方文档。

  • pCur:返回当前的状态值。

  • pHiwater:返回该状态的最高水位(例如最大内存使用量)。

  • reset:如果设置为非零值,则会重置状态统计数据(用于获取从上次调用以来的变化)。

返回值

  • 返回 SQLITE_OK 表示成功。

  • 其他错误码表示失败。

示例:

int currentUsage = 0;
int highWaterMark = 0;
int rc = sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &currentUsage, &highWaterMark, 0);
if (rc == SQLITE_OK) {std::cout << "当前缓存使用字节数: " << currentUsage << "\n";std::cout << "缓存的最高使用字节数: " << highWaterMark << "\n";
} else {std::cerr << "获取数据库状态失败\n";
}

5.事务控制

SQLite 的事务控制相对简化了一些,不像 MySQL 那样提供专门函数(mysql_autocommit、mysql_commit、mysql_rollback等)。SQLite 更注重简洁性和轻量性,因此很多事务控制操作都可以通过 sqlite3_exec 来完成,基本上是通过执行 SQL 语句来管理事务的开始、提交和回滚。

 示例:

#include <sqlite3.h>
#include <iostream>void execute_transaction(sqlite3 *db) {char *errMsg = nullptr;// 开始事务const char *beginSQL = "BEGIN TRANSACTION;";if (sqlite3_exec(db, beginSQL, nullptr, nullptr, &errMsg) != SQLITE_OK) {std::cerr << "开始事务失败: " << errMsg << "\n";sqlite3_free(errMsg);return;}// 执行插入操作const char *insertSQL = "INSERT INTO users(name) VALUES('Alice');";if (sqlite3_exec(db, insertSQL, nullptr, nullptr, &errMsg) != SQLITE_OK) {std::cerr << "插入数据失败: " << errMsg << "\n";sqlite3_free(errMsg);// 回滚事务const char *rollbackSQL = "ROLLBACK;";sqlite3_exec(db, rollbackSQL, nullptr, nullptr, &errMsg);return;}// 提交事务const char *commitSQL = "COMMIT;";if (sqlite3_exec(db, commitSQL, nullptr, nullptr, &errMsg) != SQLITE_OK) {std::cerr << "提交事务失败: " << errMsg << "\n";sqlite3_free(errMsg);return;}std::cout << "事务执行成功\n";
}int main() {sqlite3 *db = nullptr;if (sqlite3_open("test_transaction.db", &db) != SQLITE_OK) {std::cerr << "无法打开数据库: " << sqlite3_errmsg(db) << "\n";return 1;}// 执行事务execute_transaction(db);// 关闭数据库sqlite3_close(db);return 0;
}

sqlite3.h中的错误码和状态码

错误码常量名称含义描述
0SQLITE_OK操作成功
1SQLITE_ERROR通用错误
2SQLITE_INTERNALSQLite 内部逻辑错误
3SQLITE_PERM访问权限被拒绝
4SQLITE_ABORT回调函数请求中止
5SQLITE_BUSY数据库文件被锁定
6SQLITE_LOCKED数据库表被锁定
7SQLITE_NOMEM内存分配失败
8SQLITE_READONLY数据库处于只读模式,无法写入
9SQLITE_INTERRUPT操作被 sqlite3_interrupt() 中断
10SQLITE_IOERR磁盘 I/O 错误
11SQLITE_CORRUPT数据库文件损坏
12SQLITE_NOTFOUND未找到指定的操作或对象
13SQLITE_FULL数据库已满,无法插入数据
14SQLITE_CANTOPEN无法打开数据库文件
15SQLITE_PROTOCOL数据库锁协议错误
16SQLITE_EMPTY内部使用,仅供 SQLite 内部操作使用
17SQLITE_SCHEMA数据库模式(schema)变化
18SQLITE_TOOBIG字符串或二进制数据超出大小限制
19SQLITE_CONSTRAINT由于约束冲突(如 UNIQUE 或 FOREIGN KEY)导致的中止
20SQLITE_MISMATCH数据类型不匹配
21SQLITE_MISUSE错误的库调用,表示 SQLite 被错误地使用
22SQLITE_NOLFS使用了操作系统不支持的特性
23SQLITE_AUTH授权被拒绝
24SQLITE_FORMAT未使用,未定义的错误码
25SQLITE_RANGEsqlite3_bind 的参数超出范围
26SQLITE_NOTADB尝试打开一个非数据库文件
27SQLITE_NOTICE通知信息,通过 sqlite3_log() 返回
28SQLITE_WARNING警告信息,通过 sqlite3_log() 返回
100SQLITE_ROWsqlite3_step() 有一行数据可返回
101SQLITE_DONEsqlite3_step() 执行完成,所有行已处理完

相关文章:

Linux下的c/c++开发之操作Sqlite3数据库

libsqlite3-dev 介绍&#xff08;Linux 下的 SQLite3 C/C 开发包&#xff09; libsqlite3-dev 是一个开发包&#xff0c;在 Linux 环境下为使用 SQLite3 C API 进行开发的 C/C 程序员提供头文件&#xff08;如 sqlite3.h&#xff09;和静态库/动态库的链接信息&#xff08;如 …...

设计模式-策略模式

概念 策略模式主要是定义一系列算法&#xff0c;把它们封装起来&#xff0c;并且使它们可以互相替换。这样客户端可以根据需要选择不同的策略&#xff0c;而不需要改变使用策略的上下文。 策略模式的核心思想&#xff1a; 解耦策略定义&#xff1a;把各种支付方式&#xff0…...

Lost connect to debugger on ‘iphone‘

跑项目的时候&#xff0c;遇到这样一个报错&#xff0c;无法在真机和模拟器上跑&#xff0c; 处理方法 在根目录下&#xff0c;创建.lldbinit 文件 touch .lldbinit查找该文件 ls -all 然后 打开该文件 open .lldbinit 添加如下文案 settings set plugin.process.gdb-remot…...

全球森林数据如何分析?基于R语言森林生态系统结构、功能与稳定性分析与可视化

森林生态系统的结构、功能与稳定性研究是生态学领域的核心议题&#xff0c;涉及物种多样性、空间分布、能量流动及抗干扰能力等关键生态过程。为系统解析这些复杂关系&#xff0c;本研究采用R语言作为核心分析工具&#xff0c;整合多元统计方法与可视化技术&#xff0c;构建了一…...

Modbus RTU 转 PROFINE 网关

一、功能及注意事项 (1)功能说明&#xff1a;此文档用来说明Modbus RTU 转 PROFINE网关和立迈胜一体化485通讯电机使用。 (2)注意事项&#xff1a;文档介绍的是高迈德 PN-01MB模块。 二、系统参数设置 1.参考电机的波特率和校验码进行正确设置&#xff0c;如图所示&#xf…...

Redis如何实现分布式锁

Redis如何实现分布式锁 背景复盘解答被问到的问题如果过期时间没有设置好, 业务没有处理完锁就被释放了, 怎么办呢? 背景 之前被面试问到了 复盘解答 核心就是利用 set param1 nx param2 命令. set not exist 如果不存在就自行set操作. 被问到的问题 如果过期时间没有设置…...

vue3的深入组件-组件 v-model

组件 v-model 基本用法​ v-model 可以在组件上使用以实现双向绑定。 从 Vue 3.4 开始&#xff0c;推荐的实现方式是使用 defineModel() 宏&#xff1a; <script setup> const model defineModel()function update() {model.value } </script><template>…...

【Dv3Admin】Git 子模块在 Dv3admin 插件项目统一管理实践

在 Dv3admin 框架中&#xff0c;plugins 目录下存放的都是基于 Git 的独立插件项目。为了实现多个插件的统一管理与更新&#xff0c;我们推荐使用 Git 的子模块&#xff08;submodule&#xff09;功能。通过子模块的方式&#xff0c;将多个 Git 仓库嵌套管理&#xff0c;可以简…...

什么是死信队列?死信队列是如何导致的?

死信交换机&#xff08;Dead Letter Exchange&#xff0c;DLX&#xff09; 定义&#xff1a;死信交换机是一种特殊的交换机&#xff0c;专门用于**接收从其他队列中因特定原因变成死信的消息**。它的本质还是交换机&#xff0c;遵循RabbitMQ中交换机的基本工作原理&#xff0c…...

计算机网络:深入分析三层交换机硬件转发表生成过程

三层交换机的MAC地址转发表生成过程结合了二层交换和三层路由的特性,具体可分为以下步骤: 一、二层MAC地址表学习(基础转发层) 初始状态 交换机启动时,MAC地址表为空,处于学习阶段。 数据帧接收与源MAC学习 当主机A发送数据帧到主机B时,交换机会检查数据帧的源MAC地址。…...

java使用MinIO,虚拟机时间异常

使用docker进行环境部署和启动 docker pull minio/miniodocker run -d -p 9000:9000 -p 9001:9001 \-e "MINIO_ROOT_USERminio" \-e "MINIO_ROOT_PASSWORDminio123" \-v /opt/minio/data:/data \-v /opt/minio/config:/root/.minio \minio/minio server --…...

使用Jmeter进行核心API压力测试

最近公司有发布会&#xff0c;需要对全链路比较核心的API的进行压测&#xff0c;今天正好分享下压测软件Jmeter的使用。 一、什么是Jmeter? JMeter 是 Apache 旗下的基于 Java 的开源性能测试工具。最初被设计用于 Web 应用测试&#xff0c;现已扩展到可测试多种不同的应用程…...

嵌入式学习笔记 - LCD

一 显示器接口种类&#xff1a; 下图中间左边一个为不带MCU的RGB屏&#xff0c;中间右边一个为带MCU的MCU屏 带控制器的LCD屏幕跟STM32单片机的交互方式&#xff0c;可以为串口&#xff0c;也可以为SPI&#xff0c;或者8080&#xff0c;通过命令的方式对液晶控制器芯片进行操作…...

聊聊Spring AI Alibaba的SentenceSplitter

序 本文主要研究一下Spring AI Alibaba的SentenceSplitter SentenceSplitter spring-ai-alibaba-core/src/main/java/com/alibaba/cloud/ai/transformer/splitter/SentenceSplitter.java public class SentenceSplitter extends TextSplitter {private final EncodingRegis…...

Python 异常处理与文件 IO 操作:构建健壮的数据处理体系(3/10)

摘要&#xff1a;在 Python 开发中&#xff0c;异常处理和文件 IO 操作是构建稳定程序的基石。本文将深入探讨异常捕获机制、上下文管理器原理&#xff0c;并结合 JSON/CSV 数据持久化与实战项目&#xff0c;帮助你掌握应对复杂场景的核心技术。 本文深入探讨了 Python 编程中的…...

Python中,正则表达式,

目录 1.基本匹配2.量词3.边界匹配4.选择和逻辑5.示例代码 在Python中&#xff0c;正则表达式&#xff08;Regular Expressions&#xff0c;简称regex&#xff09;是一种强大的文本处理工具&#xff0c;用于匹配、查找和替换字符串中的模式。Python通过 re模块提供正则表达式支…...

CSS:元素显示模式与背景

元素显示模式 元素显示模式是指元素在浏览器页面中显示的模式&#xff0c;比如<div></div>是独占一行的块级元素&#xff0c;<span></span>是行内元素 元素显示模式分为三大类&#xff1a; 块级元素行内元素行内块元素 块级元素 block 常见的块级…...

Java游戏服务器开发流水账(2)开发中Maven的管理

Maven 是一款流行的 Java 项目管理工具&#xff0c;它基于项目对象模型&#xff08;Project Object Model&#xff0c;POM&#xff09;的概念来管理项目的构建、依赖和文档等。游戏服务器开发中也会使用. 项目构建 生命周期管理&#xff1a;Maven 定义了一套清晰的项目构建生…...

学习设计模式《八》——原型模式

一、基础概念 原型模式的本质是【克隆生成对象】&#xff1b; 原型模式的定义&#xff1a;用原型实例指定创建对象的种类&#xff0c;并通过拷贝这些原型创建新的对象 。 原型模式的功能&#xff1a; 1、通过克隆来创建新的对象实例&#xff1b; 2、为克隆出来的新对象实例复制…...

【MySQL】存储引擎 - MEMORY详解

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…...

正则表达式实用指南:原理、场景、优化与引擎对比

正则表达式实用指南&#xff1a;原理、场景、优化与引擎对比 正则表达式&#xff08;Regular Expression&#xff0c;简称 regex 或 regexp&#xff09;是程序员处理文本数据时不可或缺的“瑞士军刀”。无论是表单校验、日志分析、数据清洗&#xff0c;还是敏感信息脱敏&#…...

Python3正则表达式:字符串魔法师的指南[特殊字符]‍♂️

Python3正则表达式 什么是正则表达式&#xff1f;在Python中使用正则表达式一、正则表达式基础语法&#xff1a;你的魔法咒语基本匹配符字符类&#xff1a;性格各异的字符们预定义字符类&#xff1a;常见角色的快捷方式重复限定符&#xff1a;贪婪的收集者贪婪vs非贪婪&#xf…...

k8s术语之CronJob

CronJob管理基于时间的Job&#xff0c;即&#xff1a; 在给定时间点只运行一次 周期性地在给定时间点运行 一个CronJob对象类似于crontab文件中的一行。它根据指定的预定计划周期地运行一个Job,格式可以参考Cron 前提条件 当前使用地Kubernetes集群&#xff0c;版本>1.8.对…...

常见的提示词攻击方法 和防御手段——提示词注入(Prompt Injection)攻击解析

提示词注入&#xff08;Prompt Injection&#xff09;攻击解析 提示词注入是一种针对大型语言模型&#xff08;LLM&#xff09;的新型攻击手段&#xff0c;攻击者通过精心设计的输入文本&#xff08;提示词&#xff09;操控AI模型的输出&#xff0c;使其执行非预期行为或泄露敏…...

软件逆向工程核心技术:脱壳原理与实战分析

目录 一、脱壳技术概述&#xff1a;从保护到还原的逆向之旅 1.1 脱壳技术的本质与核心价值 1.2 壳的分类与核心技术解析 1.3 学习路径&#xff1a;从压缩壳到加密壳的渐进式突破 二、脱壳三步法&#xff1a;系统化逆向工程框架 2.1 核心流程总览 2.2 实战案例&#xff1…...

C27-简单选择排序法

一 基本思想 每轮从待排序序列中选出最小或最大的元素,与待排序区间起始位置交换,逐步缩小待排序区间 二 算法实现 遍历数组:设数组长度为n,外层循环i从0到n-2(共n-1轮) 找最小值下标:内层循环j从i1到n-1,遍历待排序区间(i到n-1),记录找最小值下标min 交换元素:将arr[i]与a…...

【Redis】持久化与事务

文章目录 1. 持久化1.1 RDB(定期)1.1.1 触发方式1.1.2 触发流程 1.2. AOF(实时)1.2.1 设置AOF1.2.2 刷新策略1.2.3 重写机制 2. 事务2.1 redis事务概念2.2 事务操作 Mysql有几个特性&#xff1a; 原子性一致性隔离性&#xff0c;redis是串行的&#xff0c;自带隔离性持久性&…...

Web 自动化之 HTML JavaScript 详解

文章目录 一、HTML 常用标签二、javascript 脚本1、什么是 javascript(js)2、 js变量和函数3、js 弹窗处理4、js 流程控制语句和 switch 结构语句应用 一、HTML 常用标签 HTML&#xff1a;超文本标记语言 超文本&#xff1a;不仅只包含文字&#xff0c;还有超链接、视频…这些…...

【JavaScript】二十九、垃圾回收 + 闭包 + 变量提升

文章目录 1、作用域1.1 局部作用域1.2 全局作用域1.3 作用域链 2、JC垃圾回收机制♻️3、GC算法3.1 引用计数法3.2 标记清除法 4、闭包4.1 定义4.2 闭包的应用&#xff1a;实现数据的私有 5、变量提升 1、作用域 即一个范围&#xff0c;离开了这个范围&#xff0c;这个变量就不…...

Python在自动驾驶实时数据处理中的应用:让AI驾驶更智能、更高效

Python在自动驾驶实时数据处理中的应用:让AI驾驶更智能、更高效 近年来,自动驾驶技术的飞速发展离不开人工智能和数据处理的支撑,而Python作为AI与数据分析的核心编程语言,在自动驾驶实时数据处理方面扮演着不可或缺的角色。从传感器数据解析,到路径规划与决策优化,再到…...

功能安全的关键——MCU锁步核技术全解析(含真实应用方案)

随着智能汽车的发展&#xff0c;整车对功能安全的要求越来越高。特别是像电动助力转向&#xff08;EPS&#xff09;、制动控制系统、气囊控制器这类对“出错零容忍”的系统&#xff0c;已经广泛采用一种重要的安全架构——锁步核&#xff08;Lockstep Core&#xff09;。 今天我…...

Java实现桶排序算法

1. 桶排序原理图解 桶排序是一种基于分桶思想的非比较排序算法&#xff0c;适用于数据分布较为均匀的场景。其核心思想是将数据分散到有限数量的“桶”中&#xff0c;每个桶再分别进行排序&#xff08;通常使用插入排序或其他简单的排序算法&#xff09;。以下是桶排序的步骤&a…...

剖析 FFmpeg:从基本功能到过滤器,实现音视频处理的灵活性

目录 1.解复用2 解码2.1 音频解码2.2 视频解码 3 修饰3.1 avio3.2 重采样 4 过滤器4.1 过滤器基本知识4.2 简单过滤器4.3 复杂滤镜图 1.解复用 解复用就是把容器中的媒体流分离出来&#xff0c;方便我们对媒体流处理。 step1&#xff1a;对媒体文件上下文初始化 AVFormatCont…...

maven如何搭建自己的私服(LINUX版)?

环境准备 安装 JDK &#xff1a;确保系统已安装 JDK 8 或更高版本。可以通过以下命令安装 JDK&#xff1a; 安装 OpenJDK &#xff1a;sudo apt update && sudo apt install openjdk-11-jdk 安装 Oracle JDK &#xff1a;需要添加第三方仓库&#xff0c;例如 WebUpd8 …...

机器视觉的手机FPC油墨丝印应用

在现代智能手机制造过程中&#xff0c;精密的组件装配和质量控制是确保产品性能和用户体验的关键。其中&#xff0c;柔性印刷电路板&#xff08;FPC&#xff09;的油墨丝印工艺尤为关键&#xff0c;它不仅影响到电路板的美观&#xff0c;更直接关系到电路的导电性能和可靠性。而…...

AI原生手机:三大技术阵营的终极对决与未来展望

引言&#xff1a;AI手机时代的真正到来 2024年&#xff0c;智能手机行业迎来了一个历史性转折点——AI原生手机从概念走向主流。根据IDC最新报告&#xff0c;中国AI手机出货量同比激增591%&#xff0c;渗透率从2023年的3%飙升至22%。这一数据背后&#xff0c;是手机厂商在硬件…...

CFCA受邀参加盛京银行手机银行7.0发布会

4月30日&#xff0c;盛京银行举办手机银行7.0发布会。 盛京银行手机银行7.0围绕“慧享生活&#xff0c;财富随行”主题&#xff0c;聚焦便捷体验、财富管理、惠民生活&#xff0c;构建12大类服务&#xff0c;升级142项功能&#xff0c;全新设置信用卡频道&#xff0c;推出“云…...

IT/OT 融合架构下的工业控制系统安全攻防实战研究

1. 引言 随着工业 4.0 和智能制造的浪潮席卷全球&#xff0c;信息技术 (IT) 与运营技术 (OT) 的融合已成为不可逆转的趋势。这种融合旨在通过实时数据交换和分析&#xff0c;打破传统的信息孤岛&#xff0c;显著提升生产效率、优化决策、降低运营成本并增强市场竞争力。IT 系统…...

AI优化高频PCB信号完整性:猎板PCB的技术突破与应用实践

随着5G通信、AI服务器及新能源汽车的快速发展&#xff0c;高频PCB的信号完整性已成为决定电子产品性能的关键。本文以猎板PCB的技术实践为例&#xff0c;解析如何通过AI算法与精密制造工艺的结合&#xff0c;实现高频信号传输的极致优化&#xff0c;为行业提供高可靠性的解决方…...

【Bluedroid】蓝牙 SDP(服务发现协议)模块代码解析与流程梳理

本文深入剖析Bluedroid蓝牙协议栈中 SDP&#xff08;服务发现协议&#xff09;服务记录的全生命周期管理流程&#xff0c;涵盖初始化、记录创建、服务搜索、记录删除等核心环节。通过解析代码逻辑与数据结构&#xff0c;揭示各模块间的协作机制&#xff0c;包括线程安全设计、回…...

obj = null; 赋值null之前没有其他引用指向obj对象,那么,当obj=null时,会被垃圾回收机制立即回收吗?

不会立即回收。 具体原因是&#xff1a; 赋值 obj null; 后&#xff0c;对象变成“不可达”&#xff0c;符合垃圾回收条件&#xff0c;但垃圾回收器并不会立刻回收它。垃圾回收是CLR自动控制的非确定性过程&#xff0c;什么时候执行回收取决于系统内存压力、GC策略、分代情况…...

Android 数据持久化之 文件存储

在 Android 开发中&#xff0c;存储文件是一个常见的需求。 本文中介绍 openFileOutput 和 File 两种不同的方式来操作文件。 一、File 方式 根据文件的存储位置和访问权限&#xff0c;可以将文件存储分为内部存储&#xff08;Internal Storage&#xff09;和外部存储&#x…...

差分OPA verilogaA 模型

做电路设计&#xff0c;需要提前用理想模型如VerilogA模型做验证。这里分享一个由ahdlib库里单端opamp改造而来的差分opamp。参考何乐年的《模拟集成电路设计与仿真》10.4节423页&#xff1b; 描述的小信号模型如上。 VerilogA 用到了SRI/C&#xff0c;GBWgm/C,gaingm*r1等概念…...

oracle goldengate非并行进程转换为并行进程

oracle goldengate非并行进程转换为并行进程 在上一期的文章中写道了直接创建并行进程的方式对大事务进行分解&#xff0c;这对于新建立同步进程的时候提前规划是很有帮助的&#xff0c;但是如果对已经进行了同步的进程重新建立需要耗时比较长&#xff0c;Oracle提供了非并行进…...

58.[前端开发-前端工程化]Day05-webpack-Git安装-配置-Git命令

Git版本控制工具详解 1 邂逅版本控制工具 认识版本控制&#xff08;版本控制&#xff09; 版本控制的功能 版本控制的历史 2 集中式和分布式区别 集中式版本控制 分布式版本控制 3 Git的环境安装搭建 Git的安装 Bash – CMD – GUI 区别 Git的配置分类 Git的配置选项 Git的…...

CF每日5题

每日刷题两小时颐养天年 1855A 800 思维 将不高兴的同学计数cnt 不高兴的同学之间两两交换&#xff0c;一定不会在 p i i p_ii pi​i的位置上&#xff0c;贡献是cnt/2 如果cnt%2>0&#xff0c;那就多交换一次 void solve() {int n;cin>>n;int cnt0;forr(i,1,n){in…...

Redis实现分布式获取全局唯一自增ID的案例。

【1】简易自增版本(从 1 开始 1,2,3&#xff0c;...) 项目结构 下面是一个基于 RedisTemplate 实现的分布式全局唯一自增 ID 生成器的案例。适用于 Java Spring Boot 环境&#xff0c;利用 Redis 的原子操作 INCR 指令。 ✅ 原理说明 Redis 提供的 INCR 命令是原子性的&…...

创建型模式:工厂方法(Factory Method)模式

一、简介 工厂方法(Factory Method)模式是一种创建型设计模式,它定义了一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。在 C# 中,工厂方法模式提供了一种更灵活的对象创建方式,将对象的创建和使用分离,提高了代码的可维护性和…...

大型语言模型在网络安全领域的应用综述

大型语言模型在网络安全领域的应用综述 简介1. 引言1.1 背景与意义1.2 LLMs 的基本概念1.3 LLMs 在网络安全中的优势1.4 报告目标 2. 文献综述方法2.1 研究问题2.2 文献检索策略2.3 文献筛选标准 3. LLMs 在网络安全领域的应用3.1 软件和系统安全 (Software and System Securit…...

TDEngine 与 Grafana

目录 实践目录 Grafana 参考文档 实践目录 10.60.100.194&#xff1a;/home/dualven/tdengine Grafana systemctl status grafana-server http://10.60.100.194:3000/ 这个端口与mydoor的new server服务冲突 &#xff08;同时只开一个&#xff09; 参考文档 运行监…...