SQLite如何用C语言实现insert操作?

99ANYc3cd6
预计阅读时长 24 分钟
位置: 首页 C语言 正文

核心步骤

在 C 语言中执行任何 SQL 语句(包括 INSERT)都遵循一个标准流程:

sqlite insert c语言
(图片来源网络,侵删)
  1. 包含头文件:引入 SQLite 的 C 语言接口头文件 sqlite3.h
  2. 打开数据库:使用 sqlite3_open() 函数,如果数据库文件不存在,它会自动创建。
  3. 准备 SQL 语句:使用 sqlite3_prepare_v2() 函数将 SQL 字符串编译成一个 SQLite 语句对象,这是为了提高效率和安全性(防止 SQL 注入)。
  4. 绑定参数:SQL 语句包含占位符(),使用 sqlite3_bind_*() 系列函数将 C 语言的变量值绑定到这些占位符上。这是防止 SQL 注入的关键步骤
  5. 执行语句:使用 sqlite3_step() 函数来执行准备好的语句,对于 INSERT 语句,当 sqlite3_step() 返回 SQLITE_DONE 时,表示执行成功。
  6. 重置和清理:使用 sqlite3_reset() 重置语句对象,以便可以重新绑定参数并执行(在循环中插入多行时非常有用),使用 sqlite3_finalize() 释放语句对象。
  7. 关闭数据库:使用 sqlite3_close() 关闭数据库连接。

完整代码示例

这个示例将创建一个名为 test.db 的数据库,其中包含一个 users 表,然后向表中插入一条新记录。

#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
// 回调函数,用于处理查询结果(本示例中INSERT不使用)
static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
    for(int i = 0; i < argc; i++) {
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("\n");
    return 0;
}
int main(int argc, char* argv[]) {
    sqlite3 *db;      // 数据库连接对象
    char *zErrMsg = 0; // 错误信息指针
    int rc;           // 返回码
    // 1. 打开数据库
    // 如果数据库文件不存在,sqlite3_open()会自动创建它
    rc = sqlite3_open("test.db", &db);
    if (rc) {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        return(1);
    } else {
        fprintf(stdout, "Opened database successfully\n");
    }
    // 2. 创建表 (如果不存在)
    const char *sql_create_table = "CREATE TABLE IF NOT EXISTS users ("
                                   "id INTEGER PRIMARY KEY AUTOINCREMENT,"
                                   "name TEXT NOT NULL,"
                                   "email TEXT NOT NULL UNIQUE,"
                                   "age INTEGER);";
    rc = sqlite3_exec(db, sql_create_table, callback, 0, &zErrMsg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    } else {
        fprintf(stdout, "Table created or already exists successfully\n");
    }
    // 3. 准备并执行 INSERT 语句 (使用参数绑定)
    const char *sql_insert = "INSERT INTO users (name, email, age) VALUES (?, ?, ?);";
    sqlite3_stmt *stmt; // 语句对象
    // 编制 SQL 语句
    rc = sqlite3_prepare_v2(db, sql_insert, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Failed to prepare statement: %s\n", sqlite3_errmsg(db));
        return 1;
    }
    // 绑定参数
    // 第一个参数是语句对象
    // 第二个参数是问号占位符的索引 (从 1 开始)
    // 第三个参数是要绑定的值
    // 第四个参数是值的长度 (对于以 null 结尾的字符串,使用 -1)
    // 第五个参数是析构函数 (通常为 NULL,表示由 SQLite 管理)
    const char *name = "张三";
    const char *email = "zhangsan@example.com";
    int age = 30;
    // 绑定 name (TEXT)
    sqlite3_bind_text(stmt, 1, name, -1, NULL);
    // 绑定 email (TEXT)
    sqlite3_bind_text(stmt, 2, email, -1, NULL);
    // 绑定 age (INTEGER)
    sqlite3_bind_int(stmt, 3, age);
    // 执行语句
    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db));
    } else {
        fprintf(stdout, "Records inserted successfully\n");
        // 获取最后插入行的 rowid
        fprintf(stdout, "Last inserted rowid: %lld\n", sqlite3_last_insert_rowid(db));
    }
    // 4. 清理语句对象
    sqlite3_finalize(stmt);
    // 5. 关闭数据库
    sqlite3_close(db);
    return 0;
}

如何编译和运行

  1. 保存代码:将上面的代码保存为 insert_example.c

  2. 编译:你需要安装 SQLite 的开发库(通常叫做 libsqlite3-devsqlite3-devel),然后使用以下命令编译:

    # Linux / macOS
    gcc insert_example.c -o insert_example -lsqlite3
    # Windows (如果你使用 MinGW)
    # gcc insert_example.c -o insert_example.exe -lsqlite3
    • -lsqlite3 告诉链接器链接 SQLite 库。
  3. 运行

    sqlite insert c语言
    (图片来源网络,侵删)
    ./insert_example

预期输出:

Opened database successfully
Table created or already exists successfully
Records inserted successfully
Last inserted rowid: 1

运行后,你会在同一目录下看到一个 test.db 文件,这就是你的 SQLite 数据库文件。


关键点详解

防止 SQL 注入的重要性

错误的做法(不安全):

char *name = "some_name";
char *sql = "INSERT INTO users (name) VALUES ('" name "');"; // 拼接字符串
sqlite3_exec(db, sql, 0, 0, &zErrMsg);

name 的值是 Robert'); DROP TABLE users; --,那么你的 SQL 语句就变成了:

sqlite insert c语言
(图片来源网络,侵删)

INSERT INTO users (name) VALUES ('Robert'); DROP TABLE users; --');

这会执行两个操作:插入一个名为 "Robert" 的用户,然后删除整个 users 表!这是灾难性的。

正确的做法(安全):

使用 作为占位符,然后用 sqlite3_bind_*() 函数绑定变量,SQLite 会安全地处理这些值,确保它们被当作数据而不是 SQL 代码的一部分来处理。

sqlite3_exec() vs. sqlite3_prepare_v2() + sqlite3_step()

  • sqlite3_exec()

    • 这是一个“便捷”函数,封装了“准备-执行-重置-清理”的全过程。
    • 适用于简单的、没有参数或一次性执行的 SQL 语句。
    • 对于 INSERT,如果只是插入一条固定数据,用它很方便。
    • 代码示例:
      const char *sql = "INSERT INTO users (name, email) VALUES ('李四', 'lisi@example.com');";
      rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
  • sqlite3_prepare_v2() + sqlite3_step()

    • 这是更底层、更灵活、更强大的方式。
    • 必须用于带参数的 SQL 语句,这是防止 SQL 注入的唯一标准方法。
    • 性能更好,因为 SQL 语句只编译一次,可以多次执行(通过循环绑定不同参数)。
    • 我们上面展示的完整示例就是使用这种方式。

在循环中插入多行

如果你想高效地插入大量数据,应该重用 sqlite3_stmt 对象。

// ... (前面的打开、创建表代码相同)
const char *sql_insert = "INSERT INTO users (name, email, age) VALUES (?, ?, ?);";
sqlite3_stmt *stmt;
rc = sqlite3_prepare_v2(db, sql_insert, -1, &stmt, NULL);
// 假设你有一个数据源
char *names[] = {"王五", "赵六", "钱七"};
char *emails[] = {"wangwu@example.com", "zhaoliu@example.com", "qianqi@example.com"};
int ages[] = {25, 32, 28};
int num_users = 3;
for (int i = 0; i < num_users; i++) {
    // 绑定新的参数值
    sqlite3_bind_text(stmt, 1, names[i], -1, NULL);
    sqlite3_bind_text(stmt, 2, emails[i], -1, NULL);
    sqlite3_bind_int(stmt, 3, ages[i]);
    // 执行
    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        fprintf(stderr, "Error inserting row %d: %s\n", i, sqlite3_errmsg(db));
        break; // 或者继续处理其他行
    }
    // 重置语句,以便下一次循环可以再次绑定和执行
    sqlite3_reset(stmt);
}
// ... (清理和关闭代码)
sqlite3_finalize(stmt);
sqlite3_close(db);
方法 优点 缺点 适用场景
sqlite3_exec() 简单、代码少 无法安全地绑定变量,性能较低 一次性执行、无参数的简单 SQL(如建表、查询单条固定数据)
prepare/step 安全(防注入)、高性能(可复用)、灵活 代码稍多,需要手动管理内存 所有带参数的 SQL 操作,特别是 INSERTUPDATEDELETE 以及需要循环插入的场景

对于任何严肃的 C 语言 SQLite 开发,强烈推荐使用 sqlite3_prepare_v2() + sqlite3_step() + sqlite3_bind_*() 的组合。

-- 展开阅读全文 --
头像
C语言如何实现优先队列?
« 上一篇 12-07
织梦编辑器段落div为何错位?
下一篇 » 12-07

相关文章

取消
微信二维码
支付宝二维码

目录[+]