【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;
}
复制代码
相关推荐
2301_803875611 天前
CSS如何制作导航栏平滑移动_使用transition与left属性
jvm·数据库·python
zxrhhm1 天前
MySQL 8.4 LTS 数据库巡检脚本
数据库·mysql
AI木马人1 天前
9.【AI任务队列实战】如何在高并发下保证系统不崩?(Redis + Celery完整方案)
数据库·人工智能·redis·神经网络·缓存
2401_883600251 天前
golang如何理解weak pointer弱引用_golang weak pointer弱引用总结
jvm·数据库·python
aLTttY1 天前
【Redis实战】分布式锁的N种实现方案对比与避坑指南
数据库·redis·分布式
2301_773553621 天前
mysql如何评估SQL语句的索引开销_mysql性能追踪与分析
jvm·数据库·python
pele1 天前
PHP源码运行受主板供电影响吗_供电相数重要性说明【技巧】
jvm·数据库·python
sinat_383437361 天前
CSS如何实现元素悬浮在页面底部_利用fixed定位与底部间距
jvm·数据库·python
gmaajt1 天前
mysql如何备份与恢复函数定义_mysql mysqldump导出存储对象
jvm·数据库·python
阿丰资源1 天前
基于SpringBoot的在线视频教育平台的设计与实现(附源码+数据库+文档,一键运行)
数据库·spring boot·后端