【sqlite】xxx.db-journal是什么?

sqlite是单文件数据库,但仅凭一个文件是做不到"先写日志,后入库,断电依然可恢复"的

那么就需要xxx.db-journal

BEGIN TRANSACTION;不会产生xxx.db-journal
CREATE TABLE不会产生xxx.db-journal
SELECT不会产生xxx.db-journal

仅当INSERT/UPDATE/DELETE时,会产生xxx.db-journal

对于一次插入操作:

  • 首先立即创建 -journal 文件并写入头信息。
  • 然后对于该语句将要修改的数据库页,先将它们的原始内容复制到 -journal 文件中。
  • 最后才执行 INSERT 语句,将修改写入内存中的数据库页缓存。

journal文件的结构如下:

offset size 描述
0 8 标头字符串:0xd9、0xd5、0x05、0xf9、0x20、0xa1、0x63、0xd7
8 4 "页数" - 日志下一段的页数,或 -1 表示所有内容到文件末尾
12 4 校验和的随机数
16 4 数据库的初始大小(以页为单位)
20 4 写入此journal的进程所假定的磁盘扇区的大小。
24 4 本journal的页面大小。
28 N 用0填充,直到填满这个扇区,是为了头不被破坏
以下3行不断重复
28+N+0 4 这个页原来是来自数据库的第几页
28+N+4 0x1000 Transaction开始前,页面原始内容,相当于整个页面拷贝过来。
28+N+4+0x1000 4 校验和的随机数,跟前面那个相等

代码如下。可以发现journal随着insert创建,一旦提交,journal就被删除。

cpp 复制代码
#include <stdio.h>
#include "sqlite3.h"

int main() {
    sqlite3* db;
    char* err_msg = NULL;
    int rc;

    // 删除之前的测试数据库(如果存在)
    remove("int.db");

    // 打开数据库连接
    rc = sqlite3_open("int.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));
        return 1;
    }
    printf("1. 数据库连接已建立\n");

    // 创建测试表
    const char* create_table_sql =
        "CREATE TABLE test_ints ("
            "tiny INT,"
            "small INT, "
            "medium INT,"
            "large INT,"
            "negative INT"
        ")";

    rc = sqlite3_exec(db, create_table_sql, NULL, NULL, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "创建表失败: %s\n", err_msg);
        sqlite3_free(err_msg);
        return 1;
    }
    printf("2. 测试表已创建\n");

    // 开始一个事务(显式开始)
    rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "开始事务失败: %s\n", err_msg);
        sqlite3_free(err_msg);
        return 1;
    }

    // 插入数据但不提交
    const char* insert_sql =
        "INSERT INTO test_ints VALUES (1, 128, 32768, 2147483647, -1);"
        "INSERT INTO test_ints VALUES (127, 255, 65535, 4294967295, -128);"
        "INSERT INTO test_ints VALUES (0, 16384, 1000000, 1000000000, -32768);";

    rc = sqlite3_exec(db, insert_sql, NULL, NULL, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "插入数据失败: %s\n", err_msg);
        sqlite3_free(err_msg);
        return 1;
    }
    printf("3. 插入数据完成\n");

    // 提交事务
    rc = sqlite3_exec(db, "COMMIT;", NULL, NULL, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "提交事务失败: %s\n", err_msg);
        sqlite3_free(err_msg);
    }
    else {
        printf("4. 事务已提交\n");
    }

    printf("5. 准备工作完成\n");

    // 开始一个事务(显式开始)
    rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "开始事务失败: %s\n", err_msg);
        sqlite3_free(err_msg);
        return 1;
    }
    printf("6. 第二次事务已开始\n");

    // 插入数据但不提交
    const char* insert_sql2 =
        "INSERT INTO test_ints VALUES (-128, -128, -128, -128, -128);";

    rc = sqlite3_exec(db, insert_sql2, NULL, NULL, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "插入数据失败: %s\n", err_msg);
        sqlite3_free(err_msg);
        return 1;
    }

    printf("7. 第二次插入完成\n");

    sqlite3_close(db);

    return 0;
}
复制代码
相关推荐
小糖学代码4 小时前
MySQL:14.mysql connect
android·数据库·mysql·adb
爬山算法5 小时前
Redis(69)Redis分布式锁的优点和缺点是什么?
数据库·redis·分布式
RestCloud5 小时前
从数据库到价值:ETL 工具如何打通南大通用数据库与企业应用
数据库
惜月_treasure6 小时前
Text2SQL与工作流实现:让数据库查询变得轻松又高效
数据库·人工智能·python
-睡到自然醒~6 小时前
[go 面试] 并发与数据一致性:事务的保障
数据库·面试·golang
为乐ovo6 小时前
19.DCL-用户管理
数据库
一个天蝎座 白勺 程序猿6 小时前
金仓数据库KingbaseES实现MongoDB平滑迁移全攻略:从架构适配到性能调优的完整实践
数据库·mongodb·数据迁移·kingbasees·金仓数据库
武子康6 小时前
Java-153 深入浅出 MongoDB 全面的适用场景分析与选型指南 场景应用指南
java·开发语言·数据库·mongodb·性能优化·系统架构·nosql
2401_837088506 小时前
Redis通用命令
数据库·redis·缓存