更新记录
0.1.0(2025-12-21) 下载此版本
初始版本,支持微信小程序使用SQLite数据库,支持数据库导入导出,支持查询插入等常用语句。
平台兼容性
uni-app(4.45)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | × | × | × | × | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|
| √ | × | × | × | × | × | × | × | × | × | × |
uni-app x(4.45)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | × | × | × | √ |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | √ | √ |
lleh-mpsqlite
SQLite 数据库插件,适用于 uni-app 小程序环境。
平台支持:目前支持微信小程序。
重要说明:不支持数据库操作直接读写数据库文件,所有修改都在内存中进行。如需持久化,需要手动调用 export() 方法导出数据库,然后保存到文件。
目录
快速开始
导入
import { sqliteOpen } from "/uni_modules/lleh-mpsqlite";
最简单的例子
// 打开空数据库
const db = await sqliteOpen(null);
// 创建表
db.run(`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER
)
`);
// 插入数据
db.run("INSERT INTO users (name, age) VALUES (?, ?)", ["Alice", 25]);
db.run("INSERT INTO users (name, age) VALUES (?, ?)", ["Bob", 30]);
// 查询数据
const result = db.exec("SELECT * FROM users");
console.log(result[0].values);
// 输出: [[1, "Alice", 25], [2, "Bob", 30]]
// 关闭数据库(重要!)
db.close();
打开数据库
sqliteOpen() 支持三种方式打开数据库:
1. 从文件路径打开
支持 .db、.sqlite 文件和 .db.br、.sqlite.br 压缩文件:
// 打开普通数据库文件
const db1 = await sqliteOpen("/static/database.db");
const db2 = await sqliteOpen("/static/database.sqlite");
// 打开压缩的数据库文件(.br 格式)
const db3 = await sqliteOpen("/static/database.db.br");
const db4 = await sqliteOpen("/static/database.sqlite.br");
2. 从 Buffer 打开
支持 ArrayBuffer 或 Uint8Array:
// 方式1:使用 uni.request 从网络获取(小程序环境)
const res = await uni.request({
url: "https://example.com/database.db",
responseType: "arraybuffer",
});
const db = await sqliteOpen(res.data);
// 方式2:读取本地文件(小程序环境)
const fs = uni.getFileSystemManager();
const fileData = await new Promise((resolve, reject) => {
fs.readFile({
filePath: "/static/database.db",
success: (res) => {
const data = new Uint8Array(res.data);
resolve(data);
},
fail: reject,
});
});
const db = await sqliteOpen(fileData);
// 方式3:直接使用 Uint8Array(示例:从已有数据创建)
const uint8Array = new Uint8Array([0x53, 0x51, 0x4c, 0x69, 0x74, 0x65]); // SQLite 文件头示例
const db = await sqliteOpen(uint8Array);
3. 创建空数据库
不传参数、传入 null 或 undefined 都可以创建空数据库:
// 创建空数据库(三种方式都可以)
const db1 = await sqliteOpen();
const db2 = await sqliteOpen(null);
const db3 = await sqliteOpen(undefined);
数据库对象方法
数据库对象(db)提供以下主要方法:
exec(sql, params?) - 执行 SQL 查询
执行 SQL 并返回所有结果,适合 SELECT 查询。支持参数绑定:
// 不带参数
const result = db.exec("SELECT * FROM users");
// 带参数(数组形式,位置参数)
const result = db.exec("SELECT * FROM users WHERE age > ?", [18]);
// 带参数(对象形式,命名参数)
const result = db.exec(
"SELECT * FROM users WHERE name = :name AND age > :age",
{
":name": "Alice",
":age": 18,
},
);
// result 是数组,每个元素包含 columns 和 values
run(sql, params?) - 执行 SQL 不返回结果
执行 SQL 但不返回数据,适合 INSERT/UPDATE/DELETE:
// 不带参数
db.run("INSERT INTO users (name, age) VALUES ('Alice', 25)");
// 带参数(数组形式)
db.run("INSERT INTO users (name, age) VALUES (?, ?)", ["Bob", 30]);
// 带参数(对象形式,命名参数)
db.run("INSERT INTO users (name, age) VALUES (:name, :age)", {
":name": "Charlie",
":age": 35,
});
prepare(sql) - 准备 SQL 语句
准备 SQL 语句,返回 Statement 对象,用于参数化查询:
// 方式1:使用位置参数(?)
const stmt = db.prepare("SELECT * FROM users WHERE age > ?");
stmt.bind([18]);
while (stmt.step()) {
const row = stmt.getAsObject();
console.log(row);
}
stmt.free(); // 必须释放
// 方式2:使用命名参数(:name)
const stmt2 = db.prepare(
"SELECT * FROM users WHERE name = :name AND age > :age",
);
stmt2.bind({ ":name": "Alice", ":age": 18 });
while (stmt2.step()) {
const row = stmt2.getAsObject();
console.log(row);
}
stmt2.free(); // 必须释放
export() - 导出数据库
将整个数据库导出为 Uint8Array。重要:数据库的所有修改都在内存中,不会自动保存。如需持久化,必须调用此方法导出并手动保存到文件。
const exported = db.export();
// exported 是 Uint8Array,可以保存为文件
// 保存文件示例
const buffer = exported.buffer.slice(
exported.byteOffset,
exported.byteOffset + exported.byteLength,
);
const fs = uni.getFileSystemManager();
fs.writeFileSync("/path/to/export.db", buffer);
create_function(name, func) - 创建自定义函数
⚠️ 小程序环境不可用:由于小程序环境的 WebAssembly 实现与标准不一致,此功能在小程序环境中不可用。
在 SQL 中调用 JavaScript 函数:
db.create_function("my_function", (x, y) => {
return x + y;
});
const result = db.exec("SELECT my_function(1, 2)");
// result[0].values[0][0] 是 3
updateHook(callback) - 注册更新钩子
⚠️ 小程序环境不可用:由于小程序环境的 WebAssembly 实现与标准不一致,此功能在小程序环境中不可用。
监听数据库的 INSERT/UPDATE/DELETE 操作:
db.updateHook((operation, database, table, rowId) => {
console.log(`${operation} on ${database}.${table} row ${rowId}`);
});
// 取消注册
db.updateHook(null);
Statement 对象方法
通过 prepare() 返回的 Statement 对象提供以下方法:
bind(params) - 绑定参数
为准备好的语句绑定参数值:
// 位置参数:SQL 中使用 ?,bind 时使用数组
const stmt1 = db.prepare("SELECT * FROM users WHERE name = ? AND age > ?");
stmt1.bind(["Alice", 18]);
// 命名参数:SQL 中使用 :name,bind 时使用对象
const stmt2 = db.prepare(
"SELECT * FROM users WHERE name = :name AND age > :age",
);
stmt2.bind({ ":name": "Alice", ":age": 18 });
step() - 执行一步
执行语句的一步,返回 true 表示还有数据,false 表示完成:
while (stmt.step()) {
// 还有数据,继续处理
}
get() / getAsObject() - 获取当前行
获取当前行的数据:
// get() 返回数组
const row = stmt.get();
// row = [1, "Alice", 25]
// getAsObject() 返回对象
const rowObj = stmt.getAsObject();
// rowObj = { id: 1, name: "Alice", age: 25 }
run(params?) - 运行语句
执行语句(适合 INSERT/UPDATE/DELETE):
// 位置参数
const stmt1 = db.prepare("INSERT INTO users (name, age) VALUES (?, ?)");
stmt1.run(["Alice", 25]);
stmt1.free();
// 命名参数
const stmt2 = db.prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
stmt2.run({ ":name": "Alice", ":age": 25 });
stmt2.free();
reset() - 重置语句
重置语句状态,可以重新绑定参数执行:
stmt.bind([18]);
while (stmt.step()) {
// 处理数据
}
stmt.reset(); // 重置后可以重新绑定参数
stmt.bind([20]);
free() - 释放语句
释放语句占用的内存,使用完必须调用:
const stmt = db.prepare("SELECT * FROM users");
// ... 使用 stmt ...
stmt.free(); // 必须释放,否则可能导致内存泄漏
完整的参数化查询示例
// 方式1:使用位置参数(?)
const stmt1 = db.prepare("SELECT * FROM users WHERE age > ? AND name LIKE ?");
stmt1.bind([18, "%Alice%"]);
while (stmt1.step()) {
const row = stmt1.getAsObject();
console.log(row.name, row.age);
}
stmt1.free(); // 必须释放
// 方式2:使用命名参数(:name)
const stmt2 = db.prepare(
"SELECT * FROM users WHERE age > :age AND name LIKE :name",
);
stmt2.bind({ ":age": 18, ":name": "%Alice%" });
while (stmt2.step()) {
const row = stmt2.getAsObject();
console.log(row.name, row.age);
}
stmt2.free(); // 必须释放
查询结果处理
exec() 返回的结果结构
exec() 返回一个数组,每个元素代表一个查询结果:
const result = db.exec("SELECT * FROM users");
// result 结构:
// [
// {
// columns: ["id", "name", "age"],
// values: [
// [1, "Alice", 25],
// [2, "Bob", 30]
// ]
// }
// ]
// 获取列名
const columns = result[0].columns;
// 获取数据行
const rows = result[0].values;
// 遍历数据
rows.forEach((row) => {
console.log(row[0], row[1], row[2]); // id, name, age
});
Statement 方式获取结果
使用 step() + get() 或 getAsObject() 逐行获取:
const stmt = db.prepare("SELECT * FROM users WHERE age > ?");
stmt.bind([18]);
// 方式1:使用 get() 获取数组
while (stmt.step()) {
const row = stmt.get();
console.log(row[0], row[1], row[2]);
}
// 方式2:使用 getAsObject() 获取对象
stmt.reset();
stmt.bind([18]);
while (stmt.step()) {
const row = stmt.getAsObject();
console.log(row.id, row.name, row.age);
}
stmt.free();
常用操作示例
创建表和插入数据
const db = await sqliteOpen(null);
// 创建表
db.run(`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER
)
`);
// 插入数据
db.run("INSERT INTO users (name, age) VALUES (?, ?)", ["Alice", 25]);
db.run("INSERT INTO users (name, age) VALUES (?, ?)", ["Bob", 30]);
db.close();
查询数据
使用 exec() 查询
// 不带参数
const result1 = db.exec("SELECT * FROM users");
// 带参数(位置参数)
const result2 = db.exec("SELECT * FROM users WHERE age > ?", [18]);
// 带参数(命名参数)
const result3 = db.exec(
"SELECT * FROM users WHERE name = :name AND age > :age",
{
":name": "Alice",
":age": 18,
},
);
result2[0].values.forEach((row) => {
console.log(row);
});
使用 prepare() 查询
// 方式1:使用位置参数(?)
const stmt1 = db.prepare("SELECT * FROM users WHERE age > ?");
stmt1.bind([18]);
while (stmt1.step()) {
const row = stmt1.getAsObject();
console.log(row);
}
stmt1.free();
// 方式2:使用命名参数(:name)
const stmt2 = db.prepare("SELECT * FROM users WHERE age > :age");
stmt2.bind({ ":age": 18 });
while (stmt2.step()) {
const row = stmt2.getAsObject();
console.log(row);
}
stmt2.free();
更新和删除数据
// 更新
db.run("UPDATE users SET age = ? WHERE name = ?", [26, "Alice"]);
// 删除
db.run("DELETE FROM users WHERE age < ?", [18]);
导出数据库
重要:数据库的所有修改都在内存中进行,不会自动保存到文件。如果需要持久化修改,必须手动调用 export() 方法导出数据库,然后保存到文件。
// 导出为 Uint8Array
const exported = db.export();
// 转换为 ArrayBuffer(如果需要)
const buffer = exported.buffer.slice(
exported.byteOffset,
exported.byteOffset + exported.byteLength,
);
// 保存文件(示例)
const fs = uni.getFileSystemManager();
const filePath = `${wx.env.USER_DATA_PATH}/database.db`;
fs.writeFileSync(filePath, buffer);
使用自定义函数
⚠️ 小程序环境不可用:由于小程序环境的 WebAssembly 实现与标准不一致,此功能在小程序环境中不可用。
// 创建自定义函数
db.create_function("greet", (name) => {
return `Hello, ${name}!`;
});
// 在 SQL 中使用
const result = db.exec("SELECT greet('Alice')");
console.log(result[0].values[0][0]); // "Hello, Alice!"
监听数据库更新
⚠️ 小程序环境不可用:由于小程序环境的 WebAssembly 实现与标准不一致,此功能在小程序环境中不可用。
db.updateHook((operation, database, table, rowId) => {
console.log(`操作: ${operation}`);
console.log(`数据库: ${database}`);
console.log(`表: ${table}`);
console.log(`行ID: ${rowId}`);
});
// 执行操作时会触发钩子
db.run("INSERT INTO users (name, age) VALUES (?, ?)", ["Alice", 25]);
// 输出: 操作: insert, 数据库: main, 表: users, 行ID: 1
// 取消监听
db.updateHook(null);
速查表
打开方式对比
| 方式 | 参数类型 | 示例 |
|---|---|---|
| 文件路径 | string |
sqliteOpen("/static/db.db") |
| 压缩文件 | string (.br) |
sqliteOpen("/static/db.db.br") |
| Buffer | ArrayBuffer / Uint8Array |
sqliteOpen(arrayBuffer) |
| 空数据库 | null / undefined |
sqliteOpen(null) |
Database 方法签名速查
| 方法 | 参数 | 返回值 | 用途 |
|---|---|---|---|
exec(sql, params?) |
SQL 字符串,可选参数 | 结果数组 | 执行查询,返回所有结果 |
run(sql, params?) |
SQL 字符串,可选参数 | 无 | 执行 SQL,不返回数据 |
prepare(sql) |
SQL 字符串 | Statement 对象 | 准备参数化查询 |
export() |
无 | Uint8Array |
导出数据库 |
create_function(name, func) |
函数名,JavaScript 函数 | 无 | 创建自定义函数(小程序环境不可用) |
updateHook(callback) |
回调函数或 null |
无 | 注册/取消更新钩子(小程序环境不可用) |
close() |
无 | 无 | 关闭数据库 |
Statement 方法签名速查
| 方法 | 参数 | 返回值 | 用途 |
|---|---|---|---|
bind(params) |
对象或数组 | 无 | 绑定参数 |
step() |
无 | boolean |
执行一步 |
get() |
无 | 数组 | 获取当前行(数组) |
getAsObject() |
无 | 对象 | 获取当前行(对象) |
run(params?) |
可选参数 | 无 | 运行语句 |
reset() |
无 | 无 | 重置语句 |
free() |
无 | 无 | 释放语句 |
exec vs run vs prepare 使用场景对比
| 方法 | 适用场景 | 示例 |
|---|---|---|
exec() |
SELECT 查询,需要所有结果,支持参数绑定 | db.exec("SELECT * FROM users WHERE age > ?", [18]) |
run() |
INSERT/UPDATE/DELETE,不需要结果,支持参数绑定 | db.run("INSERT INTO users (name, age) VALUES (?, ?)", ["Alice", 25]) |
prepare() |
需要参数化查询,或逐行处理大量数据,可重复使用 | db.prepare("SELECT * FROM users WHERE age > ?") |
重要提醒
必须调用 close() 关闭数据库
使用完数据库后,必须调用 close() 方法关闭数据库,否则会导致内存泄漏。
const db = await sqliteOpen("/static/database.db");
try {
// 使用数据库
const result = db.exec("SELECT * FROM users");
// ... 其他操作 ...
} finally {
// 确保关闭数据库
db.close();
}
必须调用 free() 释放 Statement
使用完 Statement 后,必须调用 free() 方法释放,否则可能导致内存泄漏和数据库锁定。
const stmt = db.prepare("SELECT * FROM users");
try {
while (stmt.step()) {
const row = stmt.getAsObject();
// 处理数据
}
} finally {
// 确保释放 Statement
stmt.free();
}
最佳实践
- 使用 try-finally 确保资源释放:
const db = await sqliteOpen("/static/database.db");
try {
// 使用数据库
} finally {
db.close();
}
- Statement 使用完立即释放:
const stmt = db.prepare("SELECT * FROM users");
stmt.bind([18]);
while (stmt.step()) {
// 处理数据
}
stmt.free(); // 立即释放
- 页面卸载时关闭数据库:
onUnload() {
if (this.db) {
this.db.close();
this.db = null;
}
}

收藏人数:
下载插件并导入HBuilderX
下载插件ZIP
赞赏(0)
下载 4
赞赏 0
下载 12411435
赞赏 1829
赞赏
京公网安备:11010802035340号