dbaplus社群

SQLite3 如果突发断电、关机,数据到底会不会丢?

SQLite是一个小型的数据库产品,但是其中的运维命令并不像想象的简单,这里核心的运维命令是PRAGMA,PRAGMA 语句是特定于 SQLite 的 SQL 扩展,用于修改 SQLite 库的操作或查询 SQLite 库的内部(非表)数据。PRAGMA 语句使用与其他 SQLite 命令。

这里有一个注意的地方,也就是PRAGMA命令本身,会进行更迭,同时在系统中使用错误的PRAGMA命令不会报错,这点是需要注意的。

PRAGMA 命令执行计划图

PRAGMA 命令执行计划图

下面以数据库运维中的重要性和系统性能的重要性来进行关键命令的描述。

synchronous 这里有一个表,关于sqlite3的性能和数据安全性之间的比率:

模式
数值
性能
安全性
特点说明
OFF0
★★★★★(最快)
★☆☆☆☆(最低)
不调用 fsync;掉电可能丢大量数据;适合批处理、缓存、不重要数据
NORMAL1
★★★★☆
★★☆☆☆
WAL 层 fsync 延迟到后台;掉电可能丢“最后一次提交”;推荐一般业务
FULL2
★★★☆☆
★★★★☆
每次事务提交都会 fsync;传统、稳健;TP 型业务常用
EXTRA3
★★☆☆☆(最慢)
★★★★★(最安全)
FULL + metadata fsync;确保文件元数据一致;几乎坚不可摧

这里在进入SQLite的时候需要考虑你的SQLite适用于哪种模型:

[root@localhost data]# sqlite3 test.db SQLite version 3.47.1 2024-11-25 12:07:48Enter ".help" for usage hints.sqlite> sqlite> sqlite> PRAGMA synchronous = FULL;sqlite> sqlite> PRAGMA synchronous;2sqlite> 

关键业务我们推荐FULL模式。

WAL日志刷新是SQLite一个关键的数据库运维项目,这里我们可以管控的是在断电后,到底需要多长时间数据库可以恢复工作的问题,这里就牵扯我们之前学习到了SQLite的工作模式,必须是wal然后我们的数据刷新上面提到的同步模式要是full 那么现在我们要决定的是数据页面的刷新率,也就是我们产生多少数据页面后,进行数据页面刷新的问题。

[root@localhost data]# sqlite3 test.db SQLite version 3.47.1 2024-11-25 12:07:48Enter ".help"for usage hints.sqlite> sqlite> sqlite> PRAGMA synchronous = FULL;sqlite> sqlite> PRAGMA synchronous;2sqlite> sqlite> sqlite> PRAGMA wal_autocheckpoint;1000sqlite> PRAGMA wal_autocheckpoint = 200;200sqlite> PRAGMA wal_autocheckpoint;200sqlite> PRAGMA wal_checkpoint;0|10179839|10179839sqlite> PRAGMA wal_checkpoint(TRUNCATE);0|0|0sqlite> PRAGMA wal_autocheckpoint;1000sqlite> PRAGMA wal_checkpoint;0|0|0

这里我们注意几个命令:

PRAGMA autocheckpoint;这个命令查看当前数据页面多少,才产生一次checkpoint 的工作。键入命令后会显示当前的配置是多少。

如果对数据页面触发值想进行改动,可以使用 PRAGMA wal_autocheckpint = 200; 这个意思是产生了200个页面就进行数据的刷新到磁盘的工作。

同时需要注意每次启动数据库都需要带有一个配置的文件的脚本,来加载配置否则SQLite是不会加载正确的预设配置给你。

所以你的JAVA程序在启动SQLite的时候,应该将这些写入,或者写一个脚本如下:

PRAGMA journal_mode = WAL;PRAGMA synchronous = FULL;PRAGMA wal_autocheckpoint = 200;

把这些存储在一个.sql文件中,然后启动的时候,但是在操作中我发现了一个新的问题,关于一些配置可以固化,一些不可以,这里我们总结了一个表。

一、SQLite PRAGMA 持久化 vs 非持久化

1、持久化 PRAGMA(Persistent)

这些 PRAGMA 会写入数据库文件,对所有连接永久生效。

PRAGMA
持久化
说明
journal_mode
✔
会改变数据库日志格式(如 WAL 会生成 -wal/-shm 文件)
auto_vacuum
✔
改变数据库文件结构,需要重写文件
encoding
✔(仅新库)
写入文件头,建库后不能修改
application_id
✔
写入文件头 32-bit 标识
page_size
✔
修改数据库页大小
user_version
✔
写入文件头,用于 schema 版本控制
2、会话级 PRAGMA(Non-persistent)

这些只影响当前连接或事务,不会写入数据库文件。

PRAGMA
持久化
说明
synchronous
✘
仅本连接的 IO 策略
wal_autocheckpoint
✘
WAL checkpoint 设置不写入文件
checkpoint_fullfsync
✘
仅本连接有效
analysis_limit
✘
影响 ANALYZE,本连接有效
cache_size
✘
缓存页数,内存设置
cache_spill
✘
脏页溢出策略
busy_timeout
✘
锁等待时间
automatic_index
✘
是否启用自动索引
foreign_keys
✘
每次连接都需要重新 ON
foreign_key_check
✘
检查型,不保存状态
integrity_check
✘
检查型,不保存状态
defer_foreign_keys
✘
仅当前事务有效
incremental_vacuum
✘
动作执行,不改变配置
data_version
✘
查询 DB 是否被修改
database_list
✘
查询类
index_list
 / index_info / index_xinfo
✘
查询类
`所有 deprecated PRAGMA
✘
均不持久 `

学到这里,那就出现一个问题,一个库或者一个SQLite的数据库要进行哪些初始化设置。

对新库的初始化包含了如下的设置:

1)数据库存储文本的编码 

2)数据库页面的大小 

3) 设置文件身份标识 

4)设置数据文件的版本 

5)控制SQLite是否进行磁盘空间的回收 

6)设置数据库运行的模式

下面是这六项,在LINUX 和WINDOWS 中的比对异同点。

二、SQLite 在 Linux 与 Windows 下的关键 PRAGMA 差异说明

1、数据库存储文本的编码(PRAGMA encoding)
项目
Linux
Windows
说明
默认编码
UTF-8
UTF-8
SQLite 默认 UTF-8,与 OS 无关
可设置
✔ 仅空库可设
✔ 仅空库可设
只能在创建 DB 后、建表前设
支持字符集
UTF-8 / UTF-16le / UTF-16be
同 Linux
SQLite 不验证字符集合法性
受系统终端影响
✔
✔
Windows CMD 默认 GBK,需要 chcp 65001

结论: SQLite 行为完全一致,主要差异来自 Windows 终端默认不是 UTF-8。

2、数据库页面大小(PRAGMA page_size)
项目
Linux
Windows
说明
默认页大小
4096
4096
SQLite 默认值一致
可设置范围
512–65536
同 Linux
必须在建表前设置
持久化
✔
✔
修改文件结构
性能相关
EXT4 通常 4K
NTFS 4K
两平台默认都合适

结论: 两平台行为一致,4K 页通常最佳。

3、 文件身份标识(PRAGMA application_id)
项目
Linux
Windows
说明
支持
✔
✔
完全跨平台
持久化
✔
✔
写入数据库头部 4 字节
用途
应用识别数据库类型
同 Linux
类似 meta 信息

示例:sql PRAGMA application_id = 0x1234ABCD;

项目
Linux
Windows
说明
支持
✔
✔
ORM / 迁移用
持久化
✔
✔
写入头部 32-bit 整数
典型用途
schema version 管理
同 Linux
仅给应用程序使用
项目
Linux
Windows
说明
-----------
-------
-------
------------------------------
默认值
NONE
NONE
不自动回收
FULL
✔
✔
删除数据立即收缩文件
INCREMENTAL
✔
✔
手动 PRAGMA incremental_vacuum
持久化
✔
✔
写入文件结构
文件系统影响
EXT4 更快
NTFS 较慢
仅 OS 层差异
模式
Linux
Windows
差异
--------
-----
-------
--------------
DELETE
✔
✔
一致
TRUNCATE
✔
✔
一致
PERSIST
✔
✔
一致
MEMORY
✔
✔
一致
WAL
⭐ 强
⭐ 弱一点
最大差异:锁实现不同
关键项
Linux
Windows
文件锁
POSIX fcntl
LockFileEx
并发性能
⭐ 较强
⭐ 较弱(锁开销大)
SHM 文件
.db-shm
.db-shm
值
Linux 行为
Windows 行为
说明
OFF
无 fsync
无 FlushFileBuffers
最快最不安全
NORMAL
推荐 WAL 默认
同 Linux
性能 + 数据安全折中
FULL
fsync()
FlushFileBuffers()
Windows 写盘更慢
EXTRA
FULL + metadata fsync
类似 FULL
最安全

下面是这些命令的几种集合,可以将这些进行一个标准化的设置:

1)设置数据库编码(仅空库且未建表时有效)

PRAGMA encoding = 'UTF-8';

2)设置数据库页面大小(仅空库有效)

PRAGMA page_size = 4096;

3)设置 database file 的 application id(应用识别)

PRAGMA application_id = 0x1234ABCD;

4)设置数据库 schema 版本(供程序使用)

PRAGMA user_version = 20240101;

5)设置自动回收空间模式(写入数据库文件结构)

NONE / FULL / INCREMENTAL PRAGMA auto_vacuum = FULL;

6)设置日志模式(journal_mode)

DELETE / TRUNCATE / PERSIST / MEMORY / WAL PRAGMA journal_mode = WAL;

7)设置同步级别(磁盘安全等级)

OFF / NORMAL / FULL / EXTRA PRAGMA synchronous = NORMAL;

8)WAL 模式下自动 checkpoint 间隔(不持久化,每次连接需设置)

PRAGMA wal_autocheckpoint = 200;

9) 可选:严格表(类似强类型)

CREATE TABLE t(a INTEGER, b TEXT) STRICT;

10)可选:快速收缩空间

PRAGMA incremental_vacuum;