【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;
}
复制代码
相关推荐
Jay_Franklin几秒前
Python中使用sqlite3模块和panel完成SQLite数据库中PDF的写入和读取
数据库·笔记·python·pycharm·sqlite·pdf·py
小锅巴1231 小时前
百度测开面经(分类版)
数据库·分类·数据挖掘
芒果要切1 小时前
Redis 使用场景
数据库·redis·缓存
全栈工程师修炼指南1 小时前
DBA | Oracle RMAN 实战:物理备份与数据恢复全解析
数据库·oracle·dba
现在,此刻1 小时前
clickhouse和pgSql跨库查询方案对比
数据库·sql·clickhouse·性能优化
while(1){yan}1 小时前
数据库的基本操作
数据库·oracle
翻斗花园牛图图-1 小时前
MySQL——库的操作
数据库·mysql
大猫会长2 小时前
supabase备份数据库中某个schema的方法
数据库·oracle
-指短琴长-2 小时前
MySQL快速入门——内置函数
android·数据库·mysql
小码过河.4 小时前
告别 mysqldump 痛点!用 mydumper 实现 MySQL 高效备份与恢复
数据库·mysql