一、SQLite 数据库介绍
SQLite 是一个轻量级的嵌入式关系型数据库管理系统,它以库的形式提供,不需要单独的服务器进程,直接访问存储在普通磁盘文件中的数据库。
主要特性
-
无服务器架构:SQLite 不需要单独的服务器进程
-
零配置:无需安装或管理
-
跨平台:支持所有主流操作系统
-
事务性:完全兼容 ACID (原子性、一致性、隔离性、持久性)
-
自包含:单个磁盘文件包含整个数据库
-
小型轻量:完整的库只有几百KB大小
-
公共领域:完全开源,无版权限制
数据类型
SQLite 使用动态类型系统,主要有以下存储类:
类型 | 描述 |
---|---|
NULL | 表示空值 |
INTEGER | 带符号整数,根据值大小以1、2、3、4、6或8字节存储 |
REAL | 浮点数,8字节IEEE浮点数 |
TEXT | 文本字符串,使用数据库编码(UTF-8、UTF-16BE或UTF-16LE)存储 |
BLOB | 二进制大对象,完全按照输入存储 |
类型亲和性(Type Affinity)
SQLite 支持"类型亲和性"概念,即列优先以某种特定类型存储数据。以下是五种类型亲和性:
TEXT
-
声明包含:
TEXT
,VARCHAR
,CHAR
,CLOB
等 -
将所有数据转换为文本格式存储
NUMERIC
-
声明包含:
NUMERIC
,DECIMAL
,BOOLEAN
,DATE
,DATETIME
等 -
尝试转换为INTEGER或REAL,不行则存为TEXT
INTEGER
-
声明包含:
INTEGER
,INT
,TINYINT
,SMALLINT
,MEDIUMINT
,BIGINT
等 -
行为类似NUMERIC,但无小数部分
REAL
-
声明包含:
REAL
,DOUBLE
,FLOAT
等 -
转换为REAL格式存储
BLOB
-
声明包含:
BLOB
, 或未指定类型 -
不转换,直接存储输入数据
常见数据类型映射
虽然SQLite内部只有5种存储类别,但为了兼容其他SQL数据库,支持以下类型声明:
声明的类型 | 实际亲和性 | 存储形式示例 |
---|---|---|
INTEGER, INT | INTEGER | 1, -234, 123456789012345 |
REAL, FLOAT | REAL | 3.14, -123.456, 1.23e+10 |
TEXT, VARCHAR | TEXT | 'Hello', '2023-01-01' |
BLOB | BLOB | x'53514C697465' (十六进制) |
DATE, DATETIME | NUMERIC | '2023-05-20', '2023-05-20 12:34' |
BOOLEAN | NUMERIC | 0 (false), 1 (true) |
常用属性
SQLite 提供了一系列属性和编译时选项(Pragma)来控制和查询数据库的行为。以下是常用的 SQLite 属性:
数据库配置属性(PRAGMA)
数据库设置
-
journal_mode
-
设置事务日志模式
-
可选值:DELETE(默认), TRUNCATE, PERSIST, MEMORY, WAL, OFF
-
示例:
PRAGMA journal_mode=WAL;
(启用Write-Ahead Logging模式)
-
-
synchronous
-
控制同步写入磁盘的级别
-
可选值:0(OFF), 1(NORMAL), 2(FULL-默认)
-
示例:
PRAGMA synchronous=1;
-
-
temp_store
-
控制临时表的存储方式
-
可选值:0(DEFAULT), 1(FILE), 2(MEMORY)
-
示例:
PRAGMA temp_store=2;
(内存存储临时表)
-
-
encoding
-
数据库编码
-
可选值:UTF-8, UTF-16, UTF-16le, UTF-16be
-
示例:
PRAGMA encoding="UTF-8";
-
查询设置
-
cache_size
-
设置内存缓存页数
-
示例:
PRAGMA cache_size=2000;
(约2MB缓存)
-
-
page_size
-
设置数据库页面大小(创建数据库前设置)
-
示例:
PRAGMA page_size=4096;
-
-
foreign_keys
-
启用/禁用外键约束
-
可选值:0(OFF), 1(ON)
-
示例:
PRAGMA foreign_keys=ON;
-
-
auto_vacuum
-
控制自动清理空闲空间
-
可选值:0(NONE), 1(FULL), 2(INCREMENTAL)
-
示例:
PRAGMA auto_vacuum=1;
-
信息查询
-
database_list
-
列出所有附加的数据库
-
示例:
PRAGMA database_list;
-
-
table_info(table_name)
-
获取表的列信息
-
示例:
PRAGMA table_info(users);
-
-
index_list(table_name)
-
获取表的索引列表
-
示例:
PRAGMA index_list(users);
-
-
integrity_check
-
检查数据库完整性
-
示例:
PRAGMA integrity_check;
-
-
user_version
用户自定义版本控制属性。查询当前 user_version
sql
PRAGMA user_version;
这将返回一个整数值,初始值为 0。
设置 user_version
sql
PRAGMA user_version = 版本号;
例如:
sql
PRAGMA user_version = 1;
连接属性
在编程接口中可设置的常用连接属性:
-
SQLITE_OPEN_READONLY - 只读模式打开
-
SQLITE_OPEN_READWRITE - 读写模式打开
-
SQLITE_OPEN_CREATE - 不存在时创建数据库
-
SQLITE_OPEN_URI - 允许URI文件名
-
SQLITE_OPEN_MEMORY - 内存数据库
-
SQLITE_OPEN_NOMUTEX - 多线程无互斥
-
SQLITE_OPEN_FULLMUTEX - 多线程完全互斥
版本信息属性
-
sqlite_version() - 返回SQLite版本
-
示例:
SELECT sqlite_version();
-
-
sqlite_source_id() - 返回SQLite源代码ID
-
示例:
SELECT sqlite_source_id();
-
系统状态属性
-
changes() - 返回最近操作影响的行数
-
示例:
SELECT changes();
-
-
total_changes() - 返回连接期间总更改数
-
示例:
SELECT total_changes();
-
-
last_insert_rowid() - 返回最后插入的ROWID
-
示例:
SELECT last_insert_rowid();
-
常用 SQL 命令
数据库操作
sql
-- 创建数据库(文件不存在时自动创建)
sqlite3 database_name.db
表操作
sql
-- 创建表
CREATE TABLE table_name (column1 datatype PRIMARY KEY,column2 datatype NOT NULL,column3 datatype DEFAULT value,...
);-- 删除表
DROP TABLE table_name;-- 修改表
ALTER TABLE table_name ADD COLUMN column_name datatype;
数据操作
sql
-- 插入数据
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);-- 查询数据
SELECT column1, column2, ... FROM table_name
WHERE condition
ORDER BY column ASC|DESC
LIMIT number;-- 更新数据
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;-- 删除数据
DELETE FROM table_name WHERE condition;
常用函数
SQLite 提供了丰富的内置函数来处理和转换数据,这些函数可以用于查询、计算和数据处理。以下是 SQLite 函数的分类详解和用法示例。
1. 核心函数
1.1 基本标量函数
函数 | 描述 | 示例 |
---|---|---|
COALESCE(X,Y,...) | 返回第一个非NULL参数 | SELECT COALESCE(NULL, 'default') → 'default' |
IFNULL(X,Y) | 如果X为NULL则返回Y | SELECT IFNULL(NULL, 'backup') → 'backup' |
NULLIF(X,Y) | X=Y时返回NULL,否则返回X | SELECT NULLIF(5,5) → NULL |
MAX(X,Y,...) | 返回最大值 | SELECT MAX(3,5,1) → 5 |
MIN(X,Y,...) | 返回最小值 | SELECT MIN(3,5,1) → 1 |
1.2 类型转换函数
函数 | 描述 | 示例 |
---|---|---|
CAST(expr AS type) | 类型转换 | SELECT CAST('123' AS INTEGER) → 123 |
TYPEOF(expr) | 返回存储类型 | SELECT TYPEOF(3.14) → 'real' |
2. 字符串处理函数
2.1 基本字符串函数
函数 | 描述 | 示例 |
---|---|---|
LENGTH(str) | 字符串长度(UTF-8字符数) | SELECT LENGTH('SQLite') → 6 |
LOWER(str) | 转换为小写 | SELECT LOWER('SQLite') → 'sqlite' |
UPPER(str) | 转换为大写 | SELECT UPPER('sqlite') → 'SQLITE' |
TRIM(str) | 去除两端空格 | SELECT TRIM(' SQLite ') → 'SQLite' |
LTRIM(str) | 去除左端空格 | SELECT LTRIM(' SQLite') → 'SQLite' |
RTRIM(str) | 去除右端空格 | SELECT RTRIM('SQLite ') → 'SQLite' |
2.2 高级字符串操作
函数 | 描述 | 示例 |
---|---|---|
SUBSTR(str,start,length) | 子字符串 | SELECT SUBSTR('SQLite',2,3) → 'QLi' |
REPLACE(str,old,new) | 字符串替换 | SELECT REPLACE('A-B-C','-','>') → 'A>B>C' |
HEX(blob) | BLOB转十六进制 | SELECT HEX(X'53514C697465') → '53514C697465' |
INSTR(str,substr) | 子串位置(1-based) | SELECT INSTR('SQLite','Li') → 3 |
PRINTF(format,...) | 格式化输出 | SELECT PRINTF('%.2f',3.14159) → '3.14' |
3. 数学函数
3.1 基本数学运算
函数 | 描述 | 示例 |
---|---|---|
ABS(X) | 绝对值 | SELECT ABS(-5) → 5 |
ROUND(X) | 四舍五入 | SELECT ROUND(3.14159,2) → 3.14 |
CEIL(X) /CEILING(X) | 向上取整 | SELECT CEIL(3.2) → 4 |
FLOOR(X) | 向下取整 | SELECT FLOOR(3.9) → 3 |
RANDOM() | 随机整数(-2⁶³到2⁶³-1) | SELECT RANDOM() → 随机数 |
3.2 三角函数和高级运算
函数 | 描述 | 示例 |
---|---|---|
PI() | π值 | SELECT PI() → 3.141592653589793 |
SIN(X) | 正弦(弧度) | SELECT SIN(PI()/2) → 1.0 |
COS(X) | 余弦(弧度) | SELECT COS(PI()) → -1.0 |
TAN(X) | 正切(弧度) | SELECT TAN(PI()/4) ≈ 1.0 |
ASIN(X) | 反正弦 | SELECT ASIN(1) → 1.5707963267948966 |
ACOS(X) | 反余弦 | SELECT ACOS(0) → 1.5707963267948966 |
ATAN(X) | 反正切 | SELECT ATAN(1) ≈ 0.7853981633974483 |
LOG(X) /LOG10(X) | 自然对数/10为底对数 | SELECT LOG10(100) → 2.0 |
EXP(X) | e的X次方 | SELECT EXP(1) ≈ 2.718281828459045 |
POWER(X,Y) /POW(X,Y) | X的Y次方 | SELECT POWER(2,3) → 8 |
SQRT(X) | 平方根 | SELECT SQRT(9) → 3.0 |
4. 日期和时间函数
4.1 核心日期函数
函数 | 描述 | 示例 |
---|---|---|
date(timestr,modifier,...) | 提取日期部分 | SELECT date('now') → '2023-05-20' |
time(timestr,modifier,...) | 提取时间部分 | SELECT time('now') → '14:30:45' |
datetime(timestr,modifier,...) | 日期时间 | SELECT datetime('now') → '2023-05-20 14:30:45' |
julianday(timestr,modifier,...) | Julian Day数 | SELECT julianday('2023-01-01') → 2459945.5 |
strftime(format,timestr,...) | 自定义格式 | SELECT strftime('%Y年%m月%d日','now') → '2023年05月20日' |
4.2 日期修饰符
修饰符 | 描述 | 示例 |
---|---|---|
N days | 加减天数 | SELECT date('now','+7 days') |
N hours | 加减小时 | SELECT time('now','-3 hours') |
start of month | 当月第一天 | SELECT date('now','start of month') |
weekday N | 下一个周N(0=周日) | SELECT date('now','weekday 1') → 下周一 |
unixepoch | Unix时间戳转换 | SELECT datetime(1640995200,'unixepoch') → '2022-01-01 00:00:00' |
5. 聚合函数
5.1 基本聚合函数
函数 | 描述 | 示例 |
---|---|---|
COUNT(X) | 计数 | SELECT COUNT(*) FROM users |
SUM(X) | 求和 | SELECT SUM(salary) FROM employees |
AVG(X) | 平均值 | SELECT AVG(score) FROM tests |
MIN(X) | 最小值 | SELECT MIN(price) FROM products |
MAX(X) | 最大值 | SELECT MAX(age) FROM customers |
5.2 高级聚合函数
函数 | 描述 | 示例 |
---|---|---|
GROUP_CONCAT(X[,sep]) | 连接字符串 | SELECT GROUP_CONCAT(name,', ') FROM users |
TOTAL(X) | 总是返回浮点和 | SELECT TOTAL(quantity) FROM orders |
STDEV(X) | 样本标准差(扩展) | SELECT STDEV(score) FROM tests |
VARIANCE(X) | 样本方差(扩展) | SELECT VARIANCE(price) FROM stocks |
6. 窗口函数 (SQLite 3.25.0+)
6.1 排名函数
函数 | 描述 | 示例 |
---|---|---|
ROW_NUMBER() | 行号 | SELECT name, ROW_NUMBER() OVER(ORDER BY score DESC) FROM students |
RANK() | 排名(有间隔) | SELECT name, RANK() OVER(ORDER BY score DESC) FROM students |
DENSE_RANK() | 密集排名 | SELECT name, DENSE_RANK() OVER(ORDER BY score DESC) FROM students |
NTILE(N) | 分组排名 | SELECT name, NTILE(4) OVER(ORDER BY score DESC) FROM students |
6.2 分析函数
函数 | 描述 | 示例 |
---|---|---|
LEAD(expr[,offset]) | 后行值 | SELECT date, LEAD(date) OVER(ORDER BY date) FROM events |
LAG(expr[,offset]) | 前行值 | SELECT price, LAG(price) OVER(ORDER BY date) FROM stocks |
FIRST_VALUE(expr) | 窗口首值 | SELECT name, FIRST_VALUE(score) OVER(PARTITION BY class) |
LAST_VALUE(expr) | 窗口尾值 | SELECT name, LAST_VALUE(score) OVER(PARTITION BY class) |
7. JSON函数 (SQLite 3.38.0+)
7.1 JSON处理函数
函数 | 描述 | 示例 |
---|---|---|
JSON(json) | 验证JSON | SELECT JSON('{"name":"John"}') → 1 |
JSON_ARRAY(...) | 创建JSON数组 | SELECT JSON_ARRAY(1,2,3) → '[1,2,3]' |
JSON_OBJECT(...) | 创建JSON对象 | SELECT JSON_OBJECT('id',1,'name','John') → '{"id":1,"name":"John"}' |
JSON_EXTRACT(json,path) | 提取JSON值 | SELECT JSON_EXTRACT('{"id":1}','$.id') → 1 |
JSON_INSERT(json,path,value,...) | 插入值 | SELECT JSON_INSERT('{}','$.id',1) → '{"id":1}' |
JSON_REPLACE(json,path,value,...) | 替换值 | SELECT JSON_REPLACE('{"id":1}','$.id',2) → '{"id":2}' |
JSON_SET(json,path,value,...) | 设置值 | SELECT JSON_SET('{}','$.id',1) → '{"id":1}' |
JSON_REMOVE(json,path,...) | 删除值 | SELECT JSON_REMOVE('{"id":1}','$.id') → '{}' |
8. 自定义函数
SQLite 允许用各种编程语言扩展自定义函数:
c
#include <sqlite3.h>
#include <string.h>static void reverseFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {const char *input = (const char *)sqlite3_value_text(argv[0]);int len = strlen(input);char *result = malloc(len + 1);for (int i = 0; i < len; i++) {result[i] = input[len - 1 - i];}result[len] = '\0';sqlite3_result_text(context, result, len, free);
}// 注册函数
sqlite3_create_function(db, "reverse", 1, SQLITE_UTF8, NULL, &reverseFunc, NULL, NULL);
事务控制
sql
-- 开始事务
BEGIN TRANSACTION;-- 提交事务
COMMIT;-- 回滚事务
ROLLBACK;
BEGIN TRANSACTION;-- 设置错误处理
PRAGMA foreign_keys = ON; -- 确保外键约束生效BEGIN TRY-- 删除第一张表数据DELETE FROM orders;-- 删除第二张表数据DELETE FROM order_items;-- 提交事务COMMIT;SELECT '数据删除成功' AS result;
END TRY
BEGIN CATCH-- 回滚事务ROLLBACK;SELECT '删除失败: ' || sqlite_error() AS result;
END CATCH;
索引
sql
-- 创建索引
CREATE INDEX index_name ON table_name (column_name);-- 删除索引
DROP INDEX index_name;
视图
sql
-- 创建视图
CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;-- 删除视图
DROP VIEW view_name;
触发器
sql
CREATE TRIGGER trigger_name
[BEFORE|AFTER] [INSERT|UPDATE|DELETE] ON table_name
BEGIN-- 触发器逻辑
END;
二、SQLite 加密
SQLCipher 是 SQLite 的一个开源扩展,提供了透明的 256 位 AES 数据库加密功能。以下是关于 SQLCipher 的详细介绍和使用方法。
1. SQLCipher 核心特性
-
透明的加密:使用与标准 SQLite 相同的 API
-
256 位 AES 加密:支持 CBC 和 GCM 模式
-
完整的数据库加密:包括元数据和临时文件
-
性能优化:加密操作对性能影响最小化
-
开源:基于 BSD 许可证
-
跨平台:支持 Android、iOS、Windows、macOS、Linux
2. 安装 SQLCipher
2.1 Linux/macOS 编译安装
bash
# 下载源码
git clone https://github.com/sqlcipher/sqlcipher.git
cd sqlcipher# 编译安装
./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \
LDFLAGS="-lcrypto"
make
sudo make install
2.2 Windows 预编译版本
从官方 GitHub 发布页面下载预编译的二进制文件:
https://github.com/sqlcipher/sqlcipher/releases
2.3 Android 集成
在 build.gradle 中添加依赖:
gradle
implementation 'net.zetetic:android-database-sqlcipher:4.5.0'
2.4 iOS 集成
使用 CocoaPods:
ruby
pod 'SQLCipher', '~> 4.5'
3. 基本使用方法
3.1 命令行使用
bash
# 创建加密数据库
sqlcipher encrypted.db
sqlite> PRAGMA key = 'my-secret-key';
sqlite> CREATE TABLE secret_data(id INTEGER PRIMARY KEY, data TEXT);
sqlite> .quit# 重新打开加密数据库
sqlcipher encrypted.db
sqlite> PRAGMA key = 'my-secret-key';
sqlite> .tables
3.2 Qt/C++ 使用
修改 .pro 文件:
qmake
LIBS += -lsqlcipher
代码示例:
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>int main() {QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName("encrypted.db");if (!db.open()) {qDebug() << "Error opening database:" << db.lastError().text();return -1;}QSqlQuery query;query.exec("PRAGMA key = 'my-secret-key'");if (!query.exec("CREATE TABLE IF NOT EXISTS confidential (""id INTEGER PRIMARY KEY, ""data TEXT NOT NULL)")) {qDebug() << "Create table error:" << query.lastError().text();}db.close();return 0;
}
4. 高级功能
4.1 密码变更
sql
PRAGMA rekey = 'new-secret-key';
4.2 加密现有数据库
bash
sqlcipher plaintext.db
sqlite> ATTACH DATABASE 'encrypted.db' AS encrypted KEY 'secret-key';
sqlite> SELECT sqlcipher_export('encrypted');
sqlite> DETACH DATABASE encrypted;
4.3 性能优化设置
sql
PRAGMA cipher_memory_security = OFF; -- 提高性能但降低安全性
PRAGMA cipher_page_size = 4096; -- 设置加密页大小
PRAGMA kdf_iter = 64000; -- 密钥派生迭代次数
三、SQLite 数据库管理工具
1. 跨平台工具
DB Browser for SQLite (SQLite Browser)
-
官网: DB Browser for SQLite
-
特点:
-
开源免费
-
图形化界面操作简单
-
支持数据库设计、数据浏览、SQL查询等功能
-
支持 Windows、macOS 和 Linux
-
DBeaver
-
官网: DBeaver Community | Free Universal Database Tool
-
特点:
-
开源社区版免费
-
支持多种数据库(包括SQLite)
-
强大的SQL编辑器和数据可视化功能
-
跨平台支持
-
SQLiteStudio
-
官网: SQLiteStudio
-
特点:
-
完全免费开源
-
便携版无需安装
-
内置SQL编辑器、表设计器、数据导入导出工具
-
支持插件扩展
-
2. 命令行工具
SQLite CLI (sqlite3)
-
包含于: SQLite官方发行版
-
特点:
-
官方命令行工具
-
轻量无需安装
-
支持所有SQLite功能
-
适合开发者和高级用户
-
基本用法:
bash
sqlite3 database.db
SQLite version 3.37.0 2021-12-09 14:00:00
Enter ".help" for usage hints.
sqlite> .tables # 显示所有表
sqlite> .schema users # 显示表结构
sqlite> SELECT * FROM users; # 执行查询
四、Qt 中使用 SQLite 数据库
SQLite 是 Qt 应用程序中最常用的嵌入式数据库解决方案,它轻量、高效且无需服务器。以下是 Qt 中使用 SQLite 的详细指南。
1. SQLite 基本使用
1.1 创建并连接数据库
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>// 创建数据库连接
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("my_database.db"); // 可以是内存数据库 ":memory:"if (!db.open()) {qCritical() << "Database connection error:" << db.lastError().text();return;
}
1.2 创建表
QSqlQuery query;
if (!query.exec("CREATE TABLE IF NOT EXISTS users (""id INTEGER PRIMARY KEY AUTOINCREMENT, ""username TEXT UNIQUE NOT NULL, ""password TEXT NOT NULL, ""created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)")) {qDebug() << "Create table error:" << query.lastError().text();
}
2. 基本 CRUD 操作
2.1 插入数据
// 方法1:直接执行SQL
query.exec("INSERT INTO users (username, password) VALUES ('admin', '123456')");// 方法2:使用预处理语句(推荐)
query.prepare("INSERT INTO users (username, password) VALUES (?, ?)");
query.addBindValue("user1");
query.addBindValue("654321");
if (!query.exec()) {qDebug() << "Insert error:" << query.lastError().text();
}// 方法3:使用命名占位符
query.prepare("INSERT INTO users (username, password) VALUES (:user, :pass)");
query.bindValue(":user", "user2");
query.bindValue(":pass", "qwerty");
query.exec();
2.2 查询数据
// 查询单条记录
query.prepare("SELECT username, created_at FROM users WHERE id = ?");
query.addBindValue(1);
if (query.exec() && query.next()) {QString username = query.value(0).toString();QDateTime createdAt = query.value(1).toDateTime();qDebug() << "User:" << username << "Created at:" << createdAt;
}// 查询多条记录
if (query.exec("SELECT id, username FROM users")) {while (query.next()) {int id = query.value(0).toInt();QString name = query.value(1).toString();qDebug() << "ID:" << id << "Name:" << name;}
}
2.3 更新数据
query.prepare("UPDATE users SET password = ? WHERE username = ?");
query.addBindValue("newpassword");
query.addBindValue("admin");
if (!query.exec()) {qDebug() << "Update error:" << query.lastError().text();
}
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>QSqlDatabase db = QSqlDatabase::database();
QSqlQuery query;// 方法1:使用命名占位符
query.prepare(R"(UPDATE employeesSET salary = :salary,position = :position,department = :departmentWHERE employee_id = :id
)");query.bindValue(":salary", 75000.00);
query.bindValue(":position", "Senior Developer");
query.bindValue(":department", "Engineering");
query.bindValue(":id", 1001);if (!query.exec()) {qDebug() << "更新失败:" << query.lastError().text();
}// 方法2:使用位置占位符
query.prepare(R"(UPDATE productsSET price = ?,stock = ?,last_updated = ?WHERE product_id = ?
)");query.addBindValue(29.99);
query.addBindValue(50);
query.addBindValue(QDateTime::currentDateTime());
query.addBindValue(2005);if (!query.exec()) {qDebug() << "更新失败:" << query.lastError().text();
}
2.4 删除数据
query.prepare("DELETE FROM users WHERE id = ?");
query.addBindValue(5);
if (!query.exec()) {qDebug() << "Delete error:" << query.lastError().text();
}
3. 高级特性
3.1 事务处理
db.transaction(); // 开始事务QSqlQuery query;
query.prepare("INSERT INTO users (username, password) VALUES (?, ?)");// 批量插入
QVariantList usernames, passwords;
usernames << "user3" << "user4" << "user5";
passwords << "pass3" << "pass4" << "pass5";query.addBindValue(usernames);
query.addBindValue(passwords);if (!query.execBatch()) {db.rollback(); // 回滚qDebug() << "Batch insert error:" << query.lastError().text();
} else {db.commit(); // 提交
}
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>bool deleteTablesData() {QSqlDatabase db = QSqlDatabase::database();bool success = false;// 开始事务if (!db.transaction()) {qDebug() << "开始事务失败:" << db.lastError();return false;}QSqlQuery query;// 删除第一张表数据if (!query.exec("DELETE FROM orders")) {qDebug() << "删除orders表失败:" << query.lastError();db.rollback();return false;}// 删除第二张表数据if (!query.exec("DELETE FROM order_items")) {qDebug() << "删除order_items表失败:" << query.lastError();db.rollback();return false;}// 提交事务if (!db.commit()) {qDebug() << "提交事务失败:" << db.lastError();db.rollback();return false;}qDebug() << "数据删除成功";return true;
}
3.2 使用外键约束
// 启用外键支持(SQLite默认关闭)
query.exec("PRAGMA foreign_keys = ON");// 创建有外键的表
query.exec("CREATE TABLE IF NOT EXISTS posts (""id INTEGER PRIMARY KEY AUTOINCREMENT, ""user_id INTEGER NOT NULL, ""title TEXT NOT NULL, ""content TEXT, ""FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE)");
4. 数据库管理
4.1 数据库初始化封装
class DatabaseManager {
public:static DatabaseManager& instance() {static DatabaseManager instance;return instance;}bool initialize() {db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName("app_data.db");if (!db.open()) {qCritical() << "Cannot open database:" << db.lastError();return false;}QSqlQuery query;if (!query.exec("PRAGMA foreign_keys = ON")) {qWarning() << "Failed to enable foreign keys:" << query.lastError();}return createTables();}QSqlDatabase& database() { return db; }private:DatabaseManager() {}~DatabaseManager() { db.close(); }bool createTables() {QSqlQuery query;return query.exec("CREATE TABLE IF NOT EXISTS users (""id INTEGER PRIMARY KEY AUTOINCREMENT, ""username TEXT UNIQUE NOT NULL, ""password TEXT NOT NULL)");}QSqlDatabase db;
};
4.2 数据库迁移
bool migrateDatabase() {QSqlQuery query;query.exec("PRAGMA user_version"); // SQLite特有的版本控制int version = 0;if (query.next()) {version = query.value(0).toInt();}// 版本1迁移if (version < 1) {if (!query.exec("ALTER TABLE users ADD COLUMN email TEXT")) {return false;}query.exec("PRAGMA user_version = 1");}// 版本2迁移if (version < 2) {if (!query.exec("CREATE TABLE IF NOT EXISTS settings (""user_id INTEGER PRIMARY KEY, ""theme TEXT DEFAULT 'light', ""FOREIGN KEY(user_id) REFERENCES users(id))")) {return false;}query.exec("PRAGMA user_version = 2");}return true;
}
5. 性能优化
5.1 批量插入优化
// 方法1:使用事务+批量插入
db.transaction();
QSqlQuery query;
query.prepare("INSERT INTO large_data (value) VALUES (?)");for (int i = 0; i < 10000; ++i) {query.addBindValue(QString::number(i));if (!query.exec()) {db.rollback();break;}
}
db.commit();// 方法2:使用execBatch(更高效)
db.transaction();
query.prepare("INSERT INTO large_data (value) VALUES (?)");QVariantList values;
for (int i = 0; i < 10000; ++i) {values << QString::number(i);
}query.addBindValue(values);
if (!query.execBatch()) {db.rollback();
} else {db.commit();
}
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("test.db");
db.open();QSqlQuery query;
db.transaction(); // 开始事务
query.prepare("INSERT INTO table VALUES (?, ?, ?)"); // 预处理QVariantList ids, names, ages;
ids << 1 << 2 << 3;
names << "Alice" << "Bob" << "Charlie";
ages << 25 << 30 << 28;query.addBindValue(ids);
query.addBindValue(names);
query.addBindValue(ages);if(!query.execBatch()) {qDebug() << "Batch insert failed:" << query.lastError();
}
db.commit(); // 提交事务
性能优化建议:
1)单次批量操作建议控制在100-1000条记录
2)清空绑定缓存后需调用clearBindings()
3)可调整PRAGMA设置如synchronous=OFF提升速度(但降低安全性)
5.2 索引优化
// 创建索引
query.exec("CREATE INDEX IF NOT EXISTS idx_username ON users(username)");// 查看查询计划(调试性能)
query.exec("EXPLAIN QUERY PLAN SELECT * FROM users WHERE username = 'admin'");
while (query.next()) {qDebug() << query.value(3).toString(); // 显示查询计划
}
6. 安全注意事项
6.1 防止SQL注入
// 错误方式(易受SQL注入攻击)
QString username = getUsernameFromInput(); // 用户输入
query.exec("SELECT * FROM users WHERE username = '" + username + "'");// 正确方式:使用预处理语句
query.prepare("SELECT * FROM users WHERE username = ?");
query.addBindValue(username);
query.exec();
6.2 敏感数据加密
// 使用QCryptographicHash加密密码
#include <QCryptographicHash>QString password = "user_password";
QByteArray hashed = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha256
);
QString hashedPassword = QString(hashed.toHex());// 存储加密后的密码
query.prepare("INSERT INTO users (username, password) VALUES (?, ?)");
query.addBindValue(username);
query.addBindValue(hashedPassword);
query.exec();
7. 与Qt模型/视图集成
7.1 使用QSqlTableModel
QSqlTableModel *model = new QSqlTableModel(this);
model->setTable("users");
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select();// 自定义列显示
model->setHeaderData(0, Qt::Horizontal, tr("ID"));
model->setHeaderData(1, Qt::Horizontal, tr("Username"));
model->setHeaderData(2, Qt::Horizontal, tr("Password"));// 过滤数据
model->setFilter("username LIKE '%admin%'");
model->select();// 绑定到视图
QTableView *view = new QTableView;
view->setModel(model);
view->show();
7.2 自定义SQL查询模型
class CustomSqlModel : public QSqlQueryModel {
public:explicit CustomSqlModel(QObject *parent = nullptr) : QSqlQueryModel(parent) {}QVariant data(const QModelIndex &index, int role) const override {if (role == Qt::BackgroundRole && index.column() == 2) {return QBrush(Qt::lightGray);}return QSqlQueryModel::data(index, role);}
};// 使用自定义模型
CustomSqlModel *model = new CustomSqlModel;
model->setQuery("SELECT id, username, password FROM users");
8. 在 SQLite 中插入记录并返回对应的主键
8.1. 使用 SQLite 的 last_insert_rowid() 函数
-- 插入记录
INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com');-- 获取最后插入的ID
SELECT last_insert_rowid();
8.2. Qt/C++ (QSqlQuery)
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>QSqlDatabase db = QSqlDatabase::database();
QSqlQuery query;// 插入记录
query.prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
query.bindValue(":name", "John Doe");
query.bindValue(":email", "john@example.com");if (query.exec()) {// 获取最后插入的IDQVariant id = query.lastInsertId();if (id.isValid()) {qDebug() << "插入的记录ID:" << id.toInt();} else {qDebug() << "无法获取插入ID";}
} else {qDebug() << "插入失败:" << query.lastError().text();
}
9. SQLite 存储 UTF-8 中文数据
9.1 创建 UTF-8 编码的数据库连接
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>bool createConnection()
{QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName("mydatabase.db");if (!db.open()) {qDebug() << "无法打开数据库";return false;}// 设置UTF-8编码QSqlQuery query;if (!query.exec("PRAGMA encoding = \"UTF-8\"")) {qDebug() << "设置编码失败:" << query.lastError();return false;}return true;
}
9.2 插入中文数据
bool insertUser(const QString &name, const QString &address, const QString &comment)
{QSqlQuery query;query.prepare("INSERT INTO users (name, address, comment) ""VALUES (:name, :address, :comment)");query.bindValue(":name", name.toUtf8());query.bindValue(":address", address.toUtf8());query.bindValue(":comment", comment.toUtf8());if (!query.exec()) {qDebug() << "插入数据失败:" << query.lastError();return false;}return true;
}// 调用示例
insertUser("张三", "北京市海淀区", "这是UTF-8编码的中文注释");
9.3 查询中文数据
void queryUsers()
{QSqlQuery query;if (!query.exec("SELECT id, name, address, comment FROM users")) {qDebug() << "查询失败:" << query.lastError();return;}while (query.next()) {int id = query.value(0).toInt();QString name = QString::fromUtf8(query.value(1).toByteArray());QString address = QString::fromUtf8(query.value(2).toByteArray());QString comment = QString::fromUtf8(query.value(3).toByteArray());qDebug() << "ID:" << id << "姓名:" << name << "地址:" << address<< "备注:" << comment;}
}// 条件查询
void queryUserByName(const QString &name)
{QSqlQuery query;query.prepare("SELECT id, name FROM users WHERE name = :name");query.bindValue(":name", name);if (!query.exec()) {qDebug() << "条件查询失败:" << query.lastError();return;}while (query.next()) {qDebug() << "找到用户:" << QString::fromUtf8(query.value(1).toByteArray());}
}
10. 日期时间处理
基本函数
-- 当前日期时间
SELECT datetime('now'); -- 'YYYY-MM-DD HH:MM:SS'
SELECT date('now'); -- 'YYYY-MM-DD'
SELECT time('now'); -- 'HH:MM:SS'
SELECT strftime('%Y-%m-%d %H:%M:%S', 'now'); -- 自定义格式-- 时间计算
SELECT datetime('now', '+1 day'); -- 加1天
SELECT datetime('now', '-3 hours'); -- 减3小时
SELECT datetime('now', '+2 months'); -- 加2个月
时间戳转换
-- 时间戳转日期时间
SELECT datetime(1640995200, 'unixepoch'); -- '2022-01-01 00:00:00'-- 日期时间转时间戳
SELECT strftime('%s', '2022-01-01 00:00:00'); -- 1640995200
QT实例
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDateTime>
#include <QDebug>// 插入当前时间
QSqlQuery query;
query.prepare("INSERT INTO orders (product, order_date) VALUES (?, ?)");
query.addBindValue("Keyboard");
query.addBindValue(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"));
query.exec();// 查询日期数据
if (query.exec("SELECT product, order_date FROM orders")) {while (query.next()) {QString product = query.value(0).toString();QDateTime orderDate = QDateTime::fromString(query.value(1).toString(), "yyyy-MM-dd HH:mm:ss");qDebug() << product << "ordered at" << orderDate;}
}
在 SQLite 中使用 current_time
作为字段名确实可能引起问题,因为它与 SQLite 的内置时间函数同名。
SQLite 保留的时间函数
以下是与时间相关的内置函数,最好避免用作字段名:
-
current_time
-
current_date
-
current_timestamp
-
date()
-
time()
-
datetime()
-
strftime()
-
julianday()
推荐的替代字段名
不推荐 | 推荐替代 |
---|---|
current_time | record_time , created_at , update_time |
current_date | record_date , transaction_date |
current_timestamp | last_updated , modified_at |
11. 数据库被锁定
// 设置繁忙超时时间(毫秒)
QSqlDatabase::database().setConnectOptions("QSQLITE_BUSY_TIMEOUT=30000");// 或者使用重试机制
int retries = 3;
while (retries-- > 0) {if (query.exec("SOME SQL")) break;if (query.lastError().text().contains("locked")) {QThread::msleep(100);continue;}break;
}
12. 处理大型BLOB数据
// 存储图片
QFile imageFile("photo.jpg");
if (imageFile.open(QIODevice::ReadOnly)) {QByteArray imageData = imageFile.readAll();query.prepare("INSERT INTO images (name, data) VALUES (?, ?)");query.addBindValue("profile.jpg");query.addBindValue(imageData);query.exec();
}// 读取图片
query.exec("SELECT data FROM images WHERE name = 'profile.jpg'");
if (query.next()) {QByteArray imageData = query.value(0).toByteArray();QPixmap pixmap;pixmap.loadFromData(imageData);
}