【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;
}
复制代码
相关推荐
想摆烂的不会研究的研究生6 小时前
每日八股——Redis(1)
数据库·经验分享·redis·后端·缓存
码熔burning7 小时前
MySQL 8.0 新特性爆笑盘点:从青铜到王者的骚操作都在这儿了!(万字详解,建议收藏)
数据库·mysql
猫头虎7 小时前
2025最新OpenEuler系统安装MySQL的详细教程
linux·服务器·数据库·sql·mysql·macos·openeuler
哈库纳玛塔塔7 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
@LetsTGBot搜索引擎机器人9 小时前
2025 Telegram 最新免费社工库机器人(LetsTG可[特殊字符])搭建指南(含 Python 脚本)
数据库·搜索引擎·机器人·开源·全文检索·facebook·twitter
计算机毕设VX:Fegn08959 小时前
计算机毕业设计|基于springboot + vue动物园管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
冉冰学姐9 小时前
SSM校园排球联赛管理系统y513u(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架应用·开题报告、
Tony Bai10 小时前
【分布式系统】03 复制(上):“权威中心”的秩序 —— 主从架构、一致性与权衡
大数据·数据库·分布式·架构
wb0430720111 小时前
SQL工坊不只是一个ORM框架
数据库·sql
至善迎风11 小时前
Redis完全指南:从诞生到实战
数据库·redis·缓存