eduwin + SQLite 数据库编程

SQLite 是一个自包含、零配置、嵌入式的 C 语言数据库引擎。eduwin 已将 SQLite 编译进 eduwin.lib,学生程序只需 #include "sqlite3.h" 即可直接使用,无需额外配置。


快速开始

#include "eduwin.h"
#include "sqlite3.h"

int main(void)
{
    init_app();

    sqlite3 *db = NULL;
    int rc = sqlite3_open("test.db", &db);
    if (rc != SQLITE_OK)
    {
        alert(L"错误", L"无法打开数据库");
        return 1;
    }

    char *err = NULL;
    sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS users ("
                     "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                     "name TEXT NOT NULL, "
                     "email TEXT)", NULL, NULL, &err);
    if (err)
    {
        alert(L"错误", L"建表失败");
        sqlite3_free(err);
    }

    HWND win = create_window(L"SQLite 测试", 500, 300);
    show_window(win);
    run_app();

    sqlite3_close(db);
    return 0;
}

编译命令:

build.bat

只要在 .c 文件中 #include "sqlite3.h",link 时自动从 eduwin.lib 获取 SQLite 实现。


核心 API

SQLite 最常用的三个函数:

打开/关闭

int sqlite3_open(const char *filename, sqlite3 **ppDb);
int sqlite3_close(sqlite3 *db);
  • sqlite3_open 打开或创建数据库文件(UTF-8 路径)
  • sqlite3_close 关闭数据库,释放资源
  • 返回 SQLITE_OK(0)表示成功

执行 SQL

int sqlite3_exec(sqlite3 *db, const char *sql,
                 int (*callback)(void *, int, char **, char **),
                 void *data, char **errmsg);

最简单的执行方式——不需要回调时传 NULL

sqlite3_exec(db, "INSERT INTO users VALUES(NULL, '张三', 'zhangsan@test.com')",
             NULL, NULL, &err);

带参数查询(推荐)

/* 根据学号查询用户,返回姓名,未找到返回 NULL */
const char *find_user_name(sqlite3 *db, int user_id)
{
    sqlite3_stmt *stmt = NULL;

    /* 1. 准备 SQL(?是占位符) */
    int rc = sqlite3_prepare_v2(db,
                "SELECT name FROM users WHERE id = ?",
                -1, &stmt, NULL);
    if (rc != SQLITE_OK)
        return NULL;

    /* 2. 绑定参数(第 1 个 ? 绑定 user_id) */
    sqlite3_bind_int(stmt, 1, user_id);

    /* 3. 执行查询 */
    const char *result = NULL;
    if (sqlite3_step(stmt) == SQLITE_ROW)
    {
        /* 4. 读取结果集第 0 列 */
        result = strdup((const char *)sqlite3_column_text(stmt, 0));
    }

    /* 5. 释放语句 */
    sqlite3_finalize(stmt);
    return result;
}

流程:准备 → 绑定 → 单步执行 → 读列 → 销毁

? 是占位符,从 1 开始编号。多参数时:

/* UPDATE 示例:带三个占位符 */
sqlite3_stmt *stmt;
sqlite3_prepare_v2(db,
    "UPDATE users SET name = ?, email = ? WHERE id = ?",
    -1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, name_utf8, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, email_utf8, -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt,  3, user_id);
sqlite3_step(stmt);
sqlite3_finalize(stmt);

始终使用参数绑定而非字符串拼接,可防止 SQL 注入。

获取最后插入的 ID

int last_id = (int)sqlite3_last_insert_rowid(db);

字符串编码

SQLite 的 API 使用 UTF-8 编码,而 eduwin 使用 UTF-16(宽字符)。eduwin 提供两个内置工具函数完成互转:

char *wtou8(const WCHAR *ws);
WCHAR *u8tow(const char *us);
  • wtou8:宽字符串 → UTF-8 字符串(malloc 分配内存,用完需 free
  • u8tow:UTF-8 字符串 → 宽字符串(malloc 分配内存,用完需 free

这两个函数已编译在 eduwin.lib 中,#include "eduwin.h" 即可使用。

用法:

char *sql = wtou8(L"INSERT INTO users VALUES(NULL, '测试用户', 'test@test.com')");
sqlite3_exec(db, sql, NULL, NULL, &err);
free(sql);

const char *name8 = (const char *)sqlite3_column_text(stmt, 1);
WCHAR *name16 = u8tow(name8);
set_text(label, name16);
free(name16);

完整示例:用户管理

demo\sqlite_demo.c 是一个完整的用户信息管理程序,演示了增删改查全部操作,可直接编译运行(demo\build_sqlite_demo.bat):

功能包括:

  • 列表显示所有用户(ListView)
  • 添加用户(姓名、邮箱、电话)
  • 双击列表项回填到输入框,修改后保存
  • 选中用户后删除
  • 实时搜索过滤