【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就被删除。
#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;
}