更新记录

1.0.9(2026-02-01)

修改了uniappX的最低版本

1.0.8(2026-02-01)

[优化] 更改了export方式,同时将interface.uts中的类型一并暴露 [修复] 删除了测试代码

1.0.7(2026-01-26)

优化了说明文档

查看更多

平台兼容性

uni-app x(4.87)

Chrome Safari Android Android插件版本 iOS 鸿蒙 鸿蒙插件版本 微信小程序
× × 5.0 1.0.9 × 6.0.0(20) 1.0.9 ×

其他

多语言 暗黑模式 宽屏模式

SQLite 插件说明文档

一、插件概述

1.1 插件简介

  • 该SQLite插件是基于UniApp X + UTS开发的本地数据库操作插件,封装了SQLite数据库的核心操作(连接管理、CRUD、事务、多表关联查询等),提供了 ORM面向对象的模型化开发方式,简化了原生SQLite的使用复杂度,同时保证了类型安全和操作规范性。
  • 插件使用代码风格和API设计参考了Sequelize,旨在为前端出身的开发者提供一中学习成本低、快速上手的数据库操作方案。
  • 平台适配性:支持在【Android】、【HarmonyNext】端APP中使用。

二、快速开始

2.1 安装与引入

通过HbuildX插件市场搜索【se-sqlite】安装插件:

import { SQLiteHelper } from '@/uni_modules/se-sqlite'

2.2 基础使用流程

步骤1:初始化数据库连接

// 初始化SQLiteHelper实例,参数为数据库名称(自动创建.db后缀)
// --------------------------------安卓端--------------------------------------
// 安卓端数据库的连接是同步操作,所以无需等待
const sqlite = new SQLiteHelper('demo');
// -------------------------------- 鸿蒙端 --------------------------------
// 鸿蒙端数据库的连接是异步操作,需要等待连接成功后才能执行后续操作
const sqlite = new SQLiteHelper('demo');
sqlite.open().then(() => {
  // 检查连接状态
  console.log(sqlite.isOpen()); // 输出:true
})
// 或者在异步函数内部使用
const sqlite = new SQLiteHelper('demo');
await sqlite.open();
// 检查连接状态
console.log(sqlite.isOpen()); // 输出:true

步骤2:定义数据模型

import { ModelDefType } from '@/uni_modules/se-sqlite'

-------------------------------- 基本示例 --------------------------------

const userModelDef : ModelDefType = {
  tableName: 'user', // 表名
  columns: [// 列定义
    { name: "id", type: "INTEGER", primaryKey: true, autoIncrement: true },
    { name: "name", type: "TEXT" },
    { name: "age", type: "INTEGER", default: 0 },
    { name: "createAt", type: "DATE", default: "NOW" }
  ]
};

-------------------------------- 外键示例 --------------------------------
export const houseModelDef : ModelDefType = {
  tableName: 'house', // 表名
  columns: [ // 列定义
    { name: "id", type: "INTEGER", primaryKey: true, autoIncrement: true },
    { name: "label", type: "TEXT" },
    { name: "ownerId", type: "INTEGER", notNull: true default: null },
    { name: "createAt", type: "DATE", default: "NOW" }
  ],
  foreignKeys: [ // 外键定义
    {
      field: "ownerId", // 当前表的外键字段
      refTable: "user", // 关联的主表
      refField: "id",   // 主表的关联字段
      onDelete: "CASCADE" // 级联删除:用户删除时,关联房产也删除
    }
  ]
};

-------------------------------- 唯一约束示例 --------------------------------
export const relUserHouseModelDef : ModelDefType = {
  tableName: 'relUserHouse', // 表名
  columns: [
    { name: "id", type: "INTEGER", primaryKey: true, autoIncrement: true },
    { name: "ownerId", type: "INTEGER", notNull: false },
    { name: "houseId", type: "INTEGER", notNull: false },
    { name: "createAt", type: "DATE", default: "NOW" }
  ],
  foreignKeys: [ // 外键定义(多个)
    {
      field: "ownerId", // 当前表的外键字段
      refTable: "user", // 关联的主表
      refField: "id",   // 主表的关联字段
      onDelete: "CASCADE" // 级联删除:用户删除时,关联房产也删除
    }, {
      field: "houseId", // 当前表的外键字段
      refTable: "house", // 关联的主表
      refField: "id",   // 主表的关联字段
      onDelete: "CASCADE" // 级联删除:用户删除时,关联房产也删除
    }
  ],
  uniqueKeys: [
    {
      name: "uk_owner_house", // 可选:约束名称,便于后续维护
      fields: ["ownerId", "houseId"] // 核心:这两个字段组合唯一
    }
  ]
};
// 导出默认值(建议一张表一个文件,方便维护。也可遵循个人习惯。)
export default userModelDef;
// export default houseModelDef;
// export default relUserHouseModelDef;

步骤3:挂载模型并使用

// 挂载模型(自动创建表)
const UserModel = sqlite.defineModel(userModelDef);
// defineModel方法每次调用会解析数据模型,并使用 `CREATE TABLE IF NOT EXISTS 【表名】`自动创建表结构,如果表已存在,则不会重复创建

// 基础查询
const result = UserModel.query({
  where: { age: { $gt: 18 } } // 查询年龄大于18的用户
});
console.log(result);
  • 注意: 鸿蒙端需要注意调用defineModel()前先调用sqlite.open()方法并确保数据库连接成功,否则会报错。

2.3 更多示例

2.3.1 插入数据

const result = UserModel.insert({
  name: '张三',
  age: 20
});
console.log(result);

2.3.2 批量插入数据

const result = UserModel.insertBatch([
  { name: '李四', age: 22 },
  { name: '王五', age: 25 }
]);
console.log(result);

2.3.3 批量插入数据(开启事务)

// 此方法仅鸿蒙端可用
const result = UserModel.insertBatchWithTransaction([
  { name: '李四', age: 22 },
  { name: '王五', age: 25 }
]);
console.log(result);

2.3.4 更新数据

const result = UserModel.update({
  name: '张三',
  age: 21
}, {
  where: { id: 1 } // 更新id为1的用户
});
console.log(result);

2.3.5 删除数据

const result = UserModel.delete({
  where: { id: 1 } // 删除id为1的用户
});
console.log(result);

2.3.6 查询数据

const result = UserModel.find({
  where: { age: { $gt: 18 } }, // 查询年龄大于18的用户
  orderBy: { age: "DESC" }, // 按年龄倒序排列
  limit: 10, // 限制返回条数
  offset: 0 // 跳过条数
});
console.log(result);

2.3.7 查询数据(关联查询)

const result = UserModel.findComplex({
  where: { age: { $gt: 18 } }, // 查询年龄大于18的用户
  include: [ // 关联查询
    {
      model: HouseModel, // 关联的模型(必填)
      as: 'houses', // 关联表的别名(必填)
      columns: ['id', 'label'], // 关联表查询字段(可选)
      where: { label: { $like: '%别墅%' } } // 关联条件(可选)
      targetKey: 'id',  // 外键关联字段 user表的id字段(必填)
      foreignKey: 'ownerid', // 外键 house表的ownerid字段(必填)
      // 【这里故意写错,上面定义模型字段为ownerId,但是SQLite对表名、字段名的大小写不敏感,所以能正常使用】
      required: true, // true=INNER JOIN,false=LEFT JOIN(可选)
    }
  ]
});
console.log(result);

2.3.8 查询数据(桥接关联表查询)

const result = UserModel.findComplex({
  where: { age: { $gt: 18 } }, // 查询年龄大于18的用户
  include: [ // 关联查询
    {
      model: HouseModel, // 关联的模型
      as: 'houses', // 关联表的别名
      through: {
        table: 'relUserHouse',      // 桥接表名
        as: 'rel',                  // 桥接表别名
        columns: ['id'],            // 桥接表查询字段
        mainKey: 'id',              // 当前表的主键字段
        mainForeignKey: 'ownerId',  // 当前表的外键字段
        otherKey: 'id',             // 关联表的主键字段
        otherForeignKey: 'houseId'  // 关联表的外键字段
      },
    }
  ]
});
console.log(result);

三、核心API详解

3.1 SQLiteHelper 核心类

  • SQLiteHelper 是插件的核心入口类,负责数据库连接管理、基础操作执行、模型定义等,所有数据库操作均基于此类实例。
  • Model 是基于操作表层面的方法类,所有表操作均基于 Model 实例。该类未暴漏给用户。如上的UserModel其实就是Model的实例。

3.1.1 构造函数

方法签名 说明 入参规范 注意事项
constructor(name: string) 初始化数据库实例,自动创建/连接数据库 name:数据库名称(仅字母/数字,以字母开头,不能为空) 1. 名称会自动拼接.db后缀;
2. 名称不合法会抛出异常;
3. 内部自动获取应用上下文,无需手动传入

3.1.2 连接管理

方法名 方法签名 作用 应用场景 返回值 注意事项 平台适配
isOpen isOpen(): boolean 检查数据库连接是否开启 执行操作前校验连接状态 boolean:true=已连接,false=未连接 安卓:✅️ 鸿蒙:✅️ IOS:❌️
open 安卓:open(): ExecuteResult;鸿蒙:open(): Promise<ExecuteResult> 开启/重建数据库连接 连接异常时重新连接 ExecuteResult:包含success、msg、data 已连接时返回“无需开启”提示 安卓:✅️ 鸿蒙:✅️ IOS:❌️
close close(): ExecuteResult 关闭数据库连接 页面销毁/应用退出时释放资源 ExecuteResult:包含success、msg、data 未连接时返回“无需关闭”提示 安卓:✅️ 鸿蒙:✅️ IOS:❌️

3.1.3 数据库信息查询

方法名 方法签名 作用 应用场景 返回值 注意事项 平台适配
getVersion getVersion(): string 获取SQLite版本号 调试/兼容性校验 string:版本号(如3.39.4) 未连接时抛出异常;鸿蒙平台版本号固定为3.34.0 安卓:✅️ 鸿蒙:✅️ IOS:❌️
isTableExists isTableExists(tableName: string): ExecuteResult 检查表是否存在 表操作前校验 ExecuteResult:data包含exists(是否存在)、count(表数量) 表名不能为空 安卓:✅️ 鸿蒙:✅️ IOS:❌️
getAllTableNames getAllTableNames(): ExecuteResult 查询所有用户自定义表名 数据库结构校验 ExecuteResult:data包含tableNames(表名数组)、count(表数量) 排除sqlite_开头的系统表 安卓:✅️ 鸿蒙:✅️ IOS:❌️
getTableInfo getTableInfo(tableName: string): ExecuteResult 查询表的完整结构 调试/表结构校验 ExecuteResult:data包含字段信息、创建SQL 表不存在时返回失败结果 安卓:✅️ 鸿蒙:✅️ IOS:❌️
getPath getPath(): string 获取数据库文件所在位置 调试 String 表不存在时返回失败结果 安卓:✅️ 鸿蒙:❌️ IOS:❌️
exportDbFile exportDbFile(): void 将数据库文件导出到公共目录Download下 调试/备份 - - 安卓:✅️ 鸿蒙:❌️ IOS:❌️

3.1.4 基础数据操作

方法名 方法签名 作用 应用场景 返回值 注意事项 平台适配
insert insert(table: string, values: UTSJSONObject): ExecuteResult 插入单条数据 单条数据新增 ExecuteResult:data包含rowId(新增行ID) 1. 表名/数据不能为空;
2. 自动转换数据类型(布尔值转0/1、时间转字符串)
安卓:✅️ 鸿蒙:✅️ IOS:❌️
insertBatch insertBatch(tableName: string, values: UTSJSONObject[]): ExecuteResult 批量插入数据 多条数据批量新增 ExecuteResult:data=insertIds(行ID数组) 1. 事务保障原子性;
2. 空数据会跳过并记录失败信息
安卓:✅️ 鸿蒙:✅️ IOS:❌️
insertBatchWithTransaction insertBatchWithTransaction(tableName: string, values: UTSJSONObject[]): ExecuteResult 批量插入数据 多条数据批量新增 ExecuteResult:data包含successCount(成功条数)、insertIds(行ID数组) 1. 事务保障原子性;
2. 空数据会跳过并记录失败信息
安卓:✅️ 鸿蒙:✅️ IOS:❌️
delete delete(tableName: string, whereClause: string, whereArgs: string[]): ExecuteResult 删除数据 条件删除数据 ExecuteResult:data包含deleteCount(删除行数) 1. whereClause不能为空;
2. 不支持直接删除表(删除表用runSql)
安卓:❌️鸿蒙:✅️ IOS:❌️
update update(tableName: string, values: UTSJSONObject, whereClause: string, whereArgs: string[]): ExecuteResult 更新数据 条件更新数据 ExecuteResult:data包含updateCount(更新行数) 1. 数据/条件不能为空;
2. 自动转换数据类型
安卓:✅️ 鸿蒙:✅️ IOS:❌️
query query(tableName: string, columns?: string[], whereClause?: string, whereArgs?: string[], orderBy?: string, limit?: string): ExecuteResult 通用查询 安卓:单表基础查询
鸿蒙: 兼容所有查询
ExecuteResult:data包含count(总条数)、row(数据数组) 支持分页、排序、条件过滤 安卓:✅️ 鸿蒙:✅️ IOS:❌️
queryComplex findComplex(sql: string, args?: string[], countSql?: string, countArgs?: string[]): ExecuteResult 复杂查询 多表JOIN/子查询 ExecuteResult:data包含count(总条数)、row(数据数组) 支持任意复杂SQL,自动解析多表字段为嵌套对象 安卓:✅️ 鸿蒙:❌️ IOS:❌️
runSql runSql(sqlStr: string): ExecuteResult 执行自定义SQL 建表/删表/复杂SQL操作 ExecuteResult:执行状态+消息 1. SQL不能为空;
2. 需自行保证SQL合法性
安卓:✅️ 鸿蒙:✅️ IOS:❌️

3.1.5 事务操作

方法名 方法签名 作用 应用场景 返回值 注意事项 平台适配
beginTransaction beginTransaction(): ExecuteResult 开启事务 批量操作前开启 ExecuteResult:执行状态+消息 未连接时返回失败 安卓:✅️ 鸿蒙:✅️ IOS:❌️
submitTransaction submitTransaction(): ExecuteResult 标记事务成功 批量操作成功后调用 ExecuteResult:执行状态+消息 提交前必须调用,否则事务回滚 安卓:✅️ 鸿蒙:✅️ IOS:❌️
endTransaction endTransaction(): ExecuteResult 结束事务 批量操作最后调用 ExecuteResult:执行状态+消息 无论成功失败都需调用,成功则提交,失败则回滚 安卓:✅️ 鸿蒙:❌️ IOS:❌️
rollBack rollBack(): ExecuteResult 事务回滚 批量操作异常后回滚 ExecuteResult:执行状态+消息 只有在异常失败时才能调用 安卓:❌️鸿蒙:✅️ IOS:❌️

3.1.6 模型定义

方法名 方法签名 作用 应用场景 返回值 注意事项 平台适配
defineModel defineModel(model: ModelDefType): Model 定义模型并挂载CRUD方法 模型化开发 Model:挂载了CRUD方法的模型实例 1. 自动创建表;
2. 表创建失败会抛出异常
安卓:✅️ 鸿蒙:✅️ IOS:❌️

3.2 Model 模型类

Model 类是基于模型定义生成的实例类,提供了ORM式的开发体验.封装了针对具体表的CRUD方法,无需关注底层SQL,直接通过对象方法操作数据。

  • 优点: 是开发效率高,便于维护,对于SQL语言能力薄弱,熟练开发JS的开发人员友好,不用写繁琐的SQL语句.
  • 缺点: 内部逻辑里增加了从数据模型->SQL语句的解析构建过程,转换过程有额外开销.某些复杂SQL难以用ORM表达.

3.2.1 核心方法

方法名 方法签名 作用 应用场景 入参规范 注意事项 平台适配
insert insert(data: UTSJSONObject): ExecuteResult 插入单条数据 单条数据新增 data:符合模型字段的对象 自动过滤非法字段,处理特殊类型(布尔值/时间) 安卓:✅️ 鸿蒙:✅️ IOS:❌️
insertBatch insertBatch(dataList: UTSJSONObject[]): ExecuteResult 批量插入数据 多条数据新增 dataList:符合模型字段的对象数组 事务保障原子性 安卓:✅️ 鸿蒙:✅️ IOS:❌️
insertBatchWithTransaction insertBatchWithTransaction(dataList: UTSJSONObject[]): ExecuteResult 批量插入数据 多条数据新增 dataList:符合模型字段的对象数组 事务保障原子性 安卓:❌️鸿蒙:✅️ IOS:❌️
update update(data: UTSJSONObject, options: UpdateOptions): ExecuteResult 更新数据 条件更新 data:更新数据;options:包含where条件(必填) where条件不能为空 安卓:✅️ 鸿蒙:✅️ IOS:❌️
delete delete(options: DeleteOptions): ExecuteResult 删除数据 条件删除 options:包含where条件(必填) where条件不能为空 安卓:✅️ 鸿蒙:✅️ IOS:❌️
find find(options: QueryOptions): ExecuteResult 基础查询 单表查询 options:包含columns/where/limit/offset/order 自动转换where条件为SQL 安卓:✅️ 鸿蒙:✅️ IOS:❌️
findComplex findComplex(options: ComplexQueryOptions): ExecuteResult 复杂查询 多表关联查询 options:包含columns/where/include/limit/offset/order 支持一对一/一对多/多对多关联 安卓:✅️ 鸿蒙:❌️ IOS:❌️
  • ⚠️ 注意: 鸿蒙平台的查询方法只有 find 一个封装方法,使用效果和安卓端findComplex相同. 安卓端 find和findComplex的区别在于: find适合用来查询单表数据,内部开销小.findComplex 可用来构建复杂的语句(如关联查询),内部开销大.

四、类型定义规范

4.1 核心类型说明

核心类型如下:

4.1.1 ExecuteResult 执行结果返回类型

/** 插件执行返回结果类型 */
export type ExecuteResult = {
  success : boolean;                                                // 执行是否成功
  msg ?: string;                                                       // 执行消息(失败时返回错误信息)
  data ?: UTSJSONObject | string | boolean | number | Array<any> | PageResult | null; // 结果数据
}
/** 分页查询结果类型 */
export type PageResult = {
  count : number;         // 总记录数
  row : UTSJSONObject[];  // 数据行数组
}
  • 数据示例
// 成功示例
{
  success: true,
  msg: '操作成功',
  data: {
    count: 3,
    row: [
      {id: 1, name: '张三', age: 20, createAt: '2022-01-01 12:00:00'},
      {id: 2, name: '李四', age: 20, createAt: '2022-01-01 12:00:00'},
      {id: 3, name: '王五', age: 20, createAt: '2022-01-01 12:00:00'}
    ]
  }
}

// 失败示例
{
  success: false,
  msg: 'SQL执行失败:原因:',
  data: null
}

4.1.2 ModelDefType 模型定义类型

/** 模型定义类型 */
export type ModelDefType = {
  tableName : string; // 表名
  columns : tableColumnType[]; // 字段列表
  foreignKeys ?: ForeignKeyConfig[]; // 外键配置
  uniqueKeys ?: UniqueConstraint[]; // 复合唯一约束(如 UNIQUE(ownerId, houseId))
};

/** 模型中的表字段类型 */
export type tableColumnType = {
  name : string; // 字段名
  type : "INTEGER" | "TEXT" | "REAL" | "BLOB" | "BOOLEAN" | "DATE";  // 字段类型
  primaryKey ?: boolean; // 是否主键
  autoIncrement ?: boolean; // 是否自增
  notNull ?: boolean; // 是否允许为空
  default ?: any; // 默认值
  unique ?: boolean; // 单字段是否唯一(如 unique: true 等价于 UNIQUE(字段名))
};

/** 外键定义类型 */
export type ForeignKeyConfig = {
  field : string; // 当前表的外键字段(如house.ownerId)
  refTable : string; // 关联的主表名(如user)
  refField : string; // 主表的关联字段(如user.id)
  onDelete ?: string; // 级联操作(如CASCADE/SET NULL)
  onUpdate ?: string; // 级联更新(如CASCADE)
}

/** 复合唯一约束类型 */
export type UniqueConstraint = {
  name ?: string; // 约束名称(可选,SQLite会自动生成)
  fields : string[]; // 唯一约束的字段列表(单字段:['ownerId'],复合:['ownerId', 'houseId'])
};
  • 数据示例: 参看 2.2 基础使用流程 -> 2.2.1 数据库初始化与模型导出

4.2 字段类型映射

插件支持的字段类型与SQLite原生类型的映射关系:

插件类型 SQLite原生类型 说明
INTEGER INTEGER 整数类型,支持自增/主键
TEXT TEXT 字符串类型,DATE类型也存储为TEXT
REAL REAL 浮点数类型
BLOB BLOB 二进制数据类型
BOOLEAN INTEGER 存储为0(false)/1(true)
DATE TEXT 存储为YYYY-MM-DD HH:mm:ss格式字符串,默认值NOW对应本地时间

五、最佳实践

5.1 目录结构规范

uni_modules/
└── se-sqlite/          # 插件核心目录
utils/
└── db/                     # 数据库管理目录
    ├── models/             # 模型定义目录
    │   ├── user.ts        # 用户表模型
    │   ├── house.ts       # 房产表模型
    │   └── relUserHouse.ts # 多对多关联表模型
    └── index.ts           # 数据库初始化与模型导出
pages/
└── index/
    └── index.uvue          # 业务页面使用模型

5.2 模型定义规范

  1. 表名/字段名仅包含字母/数字,且以字母开头;
  2. 主键建议命名为id,类型为INTEGER且开启autoIncrement;
  3. 一张表中建议(必须)设置一个主键,如果没有主键在复杂查询整合数据时会失败;
  4. 时间类型的字段建议将类型设为为DATE(虽然SQLite内部没有Date类型的数据),插件会自动帮你转换成TUS时间字符串。如果同时设置默认值设为 'NOW',在你新增呢个数据且美没有传该字段值时,数据库也会为你自动生成TUS时间字符串(相当于SQL: CREATE_TIME` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP);
  5. 多对多关联表建议命名为rel+主表名+关联表名(如relUserHouse)。

5.3 where 条件规范

// ------------- 正确用法示例 -------------//
SomeModel.find({
  where: { 
    a: 'hello',                           // a = 'hello'          
    $or: [{ a: 5 }, { b: { $eq: 6 }}, {c: {$in: [1, 2, 3]}} }],             // (a = 5) OR (b = 6) OR (c IN [1, 2, 3])
    $and: [{a:{$gt: 5}},{a: {$ne: 10}}],  // a > 5 AND a !=10   //1.0.5 新增
    // $or 与 $and 嵌套使用
    $or:[{a:5},{$and:[{b: {$gt: 10}}, {c:{$ne: 9}}]}],  // (a = 5) OR (b > 10 AND c != 9)
    $and: [{a:{$ne: 5}},{$or:[{b: {$gt: 1}}, {b:{$lt: 9}}]}], // a != 5 AND (b > 1 AND b < 9)
    a: {$gt: 5, $ne: 10}, // a > 5 AND a !=10
    d: {
      // 基本
      $eq: 3,                              // = 3
      $ne: 20,                             // != 20
      $is: null,                           // IS NULL
      $not: true,                          // IS NOT TRUE

      // 数字比较
      $gt: 6,                              // > 6
      $gte: 6,                             // >= 6
      $lt: 10,                             // < 10
      $lte: 10,                            // <= 10
      $between: [6, 10],                   // BETWEEN 6 AND 10
      $notBetween: [11, 15],               // NOT BETWEEN 11 AND 15

      // 其它操作符

      $in: [1, 2],                         // IN [1, 2]
      $notIn: [1, 2],                      // NOT IN [1, 2]

      $like: '%hat',                       // LIKE '%hat'
      $notLike: '%hat',                    // NOT LIKE '%hat'
      $like: ['%hat%','%cat'],              // LIKE '%hat' OR LIKE '%cat'
      $notLike: ['%hat','%cat'],           // NOT LIKE '%hat' AND NOT LIKE '%cat'
    }
  }
});
// ------------- 错误用法示例 -------------//
SomeModel.find({
  where: {           
    $or: [
      { $or: [
        {a:5},
        {c:{$gt:8}}
        ]
      }, 
      { b: 6 }
    ],  
    // $or 只能出现在where对象的第一层,其值只能是[条件对象]数组.[条件对象]只能是 {a: 5} 或 {c: {$gt: 8}这种格式
    $eq: 'hello', // where对象的第一层只能是$or和表的列名,不能是其它操作符
    d: {a: 5}.    // d代表的是列名,那么a处只能是操作符,所以这个是错误的
    e: {$between: [9,100, 300]} // $between 只能接受两个参数,所以这个是错误的
  }
});
// Model 示例的方法中会将上面的where对象解析成SQL中的where条件,由于作者能力有限,只能解析出上面这种格式的where对象,所以请尽量按照上面的正确格式来写where条件
// 如果示例中的where条件不能满足你的需求,既可以参看下方的进阶教程,自己写原生SQL.调用底层API来执行复杂的查询

5.4 事务使用示例

// 批量插入数据,事务保障
// ------------------------------- 安卓端示例 ------------------------------- //
try {
  sqlite.beginTransaction(); // 开启事务
  const result1 = UserModel.insert({ name: '张三', age: 20 });
  const result2 = HouseModel.insert({ label: '北京某小区', ownerId: result1.data.rowId });
  sqlite.submitTransaction(); // 标记事务成功
  sqlite.endTransaction(); // 结束事务(提交)
  console.log('批量插入成功');
} catch (e) {
  sqlite.endTransaction(); // 结束事务(回滚)
  console.error('批量插入失败,事务回滚:', e);
}
// 或者 
try {
  sqlite.beginTransaction(); // 开启事务
  const result1 = UserModel.insert({ name: '张三', age: 20 });
  const result2 = HouseModel.insert({ label: '北京某小区', ownerId: result1.data.rowId });
  sqlite.submitTransaction(); // 标记事务成功
  console.log('批量插入成功');
} catch (e) {
  console.error('批量插入失败,事务回滚:', e);
} final {  
  // 无论成功与否,最终都需要调用endTransaction结束事务,否则会阻塞后续操作
  // 所以只要是开启了事务,一定要保证后续代码能够执行到endTransaction
  sqlite.endTransaction(); // 结束事务(回滚)
}
// ------------------------------- 鸿蒙端示例 ------------------------------- //
let t: ExecuteResult | null = null
try {
  const openResult =  sqlite.beginTransaction(); // 开启事务
  t= openResult
  if(!openResult.success) {
    throw new Error('事务开启失败');
  }
  const result1 = UserModel.insert({ name: '张三', age: 20 });
  const result2 = HouseModel.insert({ label: '北京某小区', ownerId: result1.data.rowId });
  const submitResult = sqlite.submitTransaction(); // 标记事务成功
  if(!submitResult.success) {
    throw new Error('事务提交失败');
  }
} catch (e) {
  if(t.success) {
    sqlite.rollBack(); // 回滚事务
  }
}
// --------------- ⚠️ 注意以上 安卓端 和 鸿蒙端 对于事务的处理方式的不同 ⚠️ --------------- //

5.5 复杂查询时的注意事项

// 示例1. A->B 关联查询
const result = UserModel.queryComplex({
  columns: ['name', 'age'], // 指定查询字段
  where: { name: '张三' }, // 查询条件
  include: [
    {
      model: HouseModel, // 关联模型
      required: false, // 是否必须关联,为true时无关联数据会被过滤只返回有关联的数据.比如张三名下没房产,则不会返回张三的数据
      as: 'house', // 关联表别名 ⚠️ 此处别名的命名注意不要和 UserModel 中的字段名冲突()
      foreignKey: 'ownerId', // 外键字段 ⚠️ 必须指定
      targetKey: 'id', // 关联表主键 ⚠️ 必须指定
    }, 
  ],
});

// 示例2. A<- B ->C 通过中间表关联查询
const result2 = UserModel.findComplex({
  columns: ['name', 'age'], // 指定查询字段
  include: [{
    model: HouseModel.modelDef,
    as: 'houses',
    columns: ['id', 'label'],
    required: true,
    through: {
      table: 'relUserHouse',     // 中间表名称
      as: 'rel',                 // 中间表别名 (非必填)
      columns: ['id'],           // 中间表字段 (非必填)
      mainKey: 'id',             //⚠️ 必须指定
      mainForeignKey: 'ownerId', //⚠️ 必须指定
      otherKey: 'id',            //⚠️ 必须指定
      otherForeignKey: 'houseId' //⚠️ 必须指定
      // 通过中间表关联查询时,中间表必须存在,否则会抛出异常
      // 一般情况下,中间表作为桥接作用,as 和 columns 可以不指定,因为中间表一般只存储两个表的外键.除非有业务场景需要确定 user和house的关联时间时才需要指定 as 和 columns
    },
  }],
  limit: 10,
  offset: 20
})

5.5 批量插入时的注意事项

  1. insertBatch 在本插件中都是经过封装后的方法,但内部调用的底层逻辑不同.
  2. 安卓端: insertBatch 内部启用了事务,通过遍历数据->循环插入单条来实现的,所以批量插入时,如果中途抛出异常,事务会回滚,插入的数据会全部失效. ⚠️ 因内部启用了事务,所以不要再其它事务中调用 insertBatch以免造成事务嵌套
  3. 鸿蒙端: insertBatch 调用的是鸿蒙原生的RelationalStore.RdbStore.batchInsertSync方法.非循环操作,所以内部无事务. ⚠️但这里有个注意点是batchInsertSync底层执行的是INSERT OR IGNORE 语法.所以存在一种情况就是如上方relUserHouse表,虽然有Unique约束,但插入的数据中如果存在重复数据,鸿蒙端会忽略这些重复数据,不会抛出异常.而且如果该表的主键支持自增,在你反复插入同一条数据时,该条数据的id会不断自增,但表中数据的总数不变.
  4. 考虑到3中的情况,插件中在鸿蒙端独有一个insertBatchWithTransaction方法,内部逻辑和安卓端insertBatch一样,开启事务+循环插入单条.所以如果需要保证数据一致性,请使用insertBatchWithTransaction方法.

5.6 groupBy 和 having 示例

  • 示例一 单表聚合查询
const result = UserModel.findComplex({
  columns: [
    'id',
    'name',
    { func: 'COUNT', field: 'id', as: 'counts'},
    { func: 'SUM', field: 'amount', as: 'totalAmount'},
    { func: 'MAX', field: 'amount', as: 'maxAmount'},
  ],
  where: { id: { $gt: 1 } },
  groupBy: ['id', 'name'], // 按照SQLite的兼容性,上面colums里有几个表原始字段,这里就要写几个字段(豆包说的,我也不懂)
  having: { counts: { $gte: 2 }, totalAmount: { $gte: 500 } },
  order: [['totalAmount', 'DESC']],
  offset: 0,
  limit: 10
})
console.log(result)
--示例一得到的SQL语句:
SELECT
    main.id,
    main.name,
    COUNT(main.id2) AS counts,
    SUM(main.amount) AS totalAmount,
    MAX(main.amount) AS maxAmount
FROM user main
WHERE (main.id > ?)
GROUP BY
    main.id,
    main.name
HAVING (
        counts >= ?
        AND totalAmount >= ?
    )
ORDER BY totalAmount DESC
LIMIT 10
OFFSET 0;
  • 示例二 联合查询聚合
const result = UserModel.findComplex({
      columns: [
        'id',
        'name',
        { func: 'COUNT', field: 'id2', as: 'counts', targetTable: 'bills' },
        { func: 'SUM', field: 'amount', as: 'totalAmount', targetTable: 'bills' },
        { func: 'MAX', field: 'amount', as: 'maxAmount', targetTable: 'bills' },
      ],
      where: { id: { $gt: 1 } },
      include: [
        {
          model: BillModel.modelDef,
          as: 'bills',
          columns: [],
          targetKey: 'id',
          foreignKey: 'ownerId',
          required: false,
          order: [['id', 'DESC']],
          where: { status: 1, createAt: { $gte: '2025-01-01', $lt: '2026-01-01' } }
        }
      ],
      groupBy: ['id', 'name'],
      having: { counts: { $gte: 2 }, totalAmount: { $gte: 500 } },
      order: [['totalAmount', 'DESC']],
      offset: 0,
      limit: 10
    })
    console.log(result)
-- 示例二 得到的SQL语句
ELECT
    main.id,
    main.name,
    COUNT(bill.id2) AS counts,
    SUM(bill.amount) AS totalAmount,
    MAX(bill.amount) AS maxAmount,
    bill.id AS bill_id
FROM user main
    LEFT JOIN bill bill ON main.id = bill.ownerId
    AND bill.id IN (
        SELECT bill.id
        FROM bill bill
        WHERE
            bill.ownerId = main.id
            AND (
                bill.createAt >= ?
                AND bill.createAt < ?
                AND bill.status = ?
            )
    )
WHERE (main.id > ?)
GROUP BY
    main.id,
    main.name
HAVING (
        counts >= ?
        AND totalAmount >= ?
    )
ORDER BY totalAmount DESC
LIMIT 10
OFFSET
    0;
  • 注意事项:
  1. ⚠️ 目前聚合函数仅支持: 'COUNT' | 'SUM' | 'MAX' | 'MIN' | 'AVG';
  2. ⚠️ 示例二 中的 targetTable 字段要与当前字段所属表的别名相同. 比如: { func: 'SUM', field: 'amount', as: 'totalAmount', targetTable: 'bills' }, ,amount 字段其实是 bill表中的字段,而下方include 语句中 bill表将别名改成了 bills (as: 'bills'). 所以 targetTable这个字段的值要与 as 的值相同.

六、注意事项

6.1 通用注意事项

  1. 创建表的过程建议使用defineModel方法,避免手动编写SQL,提高开发效率;
  2. 数据库名称/表名/字段名仅支持字母/数字,且必须以字母开头,否则会抛出异常;
  3. 所有操作均需保证数据库连接已开启(isOpen返回true),否则会返回失败结果;
  4. 批量操作建议使用事务,避免部分成功部分失败;
  5. 查询结果的游标会自动关闭,无需手动处理,但复杂查询需注意结果集大小,避免内存溢出;
  6. 外键约束需在模型定义中配置,SQLite默认开启外键支持,插件已适配。

6.2 性能注意事项

  1. 大量数据查询建议使用分页(limit/offset),避免一次性查询全部数据;
  2. 多表关联查询尽量指定columns,只查询需要的字段,减少数据传输;
  3. 频繁的插入/更新操作建议使用批量方法(insertBatch),减少数据库IO;

6.3 兼容性注意事项

  1. 该插件目前支持Android端/鸿蒙端,基于UniApp X的UTS开发,不支持iOS/小程序;
  2. SQLite版本由设备系统决定,插件已兼容主流版本(3.x)。

七、进阶教程

  • 由于插件 ORM 模式开发的局限性(无法构建复杂的SQL语句,并保证SQL性能),所以为保证能够适配复杂业务场景,本插件提供了底层API来执行复杂的查询.允许用户自己构建sql语句来执行.对比 ORM 开发模式, 直接调用底层API基本无额外消耗,且灵活度更高,适配场景更广,但对于开发者的SQL语言的水平要求也更高.

7.1 安卓端进阶教程

7.1.1 runSql(sql: string) : ExecuteResult

  • 底层API execSQL(String sql)
  • 作用:执行无返回结果的原生 SQL 语句;
  • 支持操作:建表、删表、ALTER 语句、INSERT/UPDATE/DELETE(无返回值)、创建索引等;
  • 使用场景:执行非查询类原生 SQL,无需获取执行结果;
  • 示例
    // 执行建表SQL
    sqlite.runSql("CREATE TABLE IF NOT EXISTS house (id INTEGER PRIMARY KEY, ownerId INTEGER)");
    // 执行插入SQL
    sqlite.runSqlL("INSERT INTO house (ownerId) VALUES (1)");
    // 执行删除SQL
    sqlite.runSql("DELETE FROM house WHERE ownerId = 1");
    // 返回结果:
    {
    success: true, // true: 标识SQL语句执行成功  false: 标识SQL语句执行失败
    msg: '执行成功', // 当实行失败时,这里展示报错信息
    dataL: null
    } 

    7.1.2 rawQuery(sql : string, args : string[]) : ExecuteResult

  • 底层API rawQuery(String sql, String[] selectionArgs)
  • 作用:执行有返回结果的原生 SQL 语句(仅 SELECT);
  • 参数sql - 原生查询 SQL(可带占位符 ?),selectionArgs - 占位符对应的参数数组(按顺序匹配,避免SQL注入);
  • 返回值Cursor - 查询结果集,需遍历处理,使用后必须关闭;
  • 使用场景:复杂查询(多表关联、GROUP BY、HAVING、子查询等),封装方法无法实现时;
  • 示例
const sql = `SELECT * FROM user WHERE age > ? AND name LIKE ?`
const args = ["20", "%张%"] 
const result = sqlite.rawQuery(sql,args); 
// 该方法内部对返回结果只进行了简单的便利转化,所以复杂的联合查询结果是扁平化的json数据,需要用户自己处理数据结构
console.log(result)

// 返回结果:
{
  success: true, // true: 标识SQL语句执行成功  false: 标识SQL语句执行失败
  msg: '执行成功', // 当实行失败时,这里展示报错信息
  dataL: [
    ...
  ]
} 

7.2 鸿蒙端进阶教程

7.2.1 runSql(sql: string) : ExecuteResult

  • 底层API executeSync(sql: string, args?: Array<ValueType>): ValueType
  • 作用:执行无返回结果的原生 SQL 语句;
  • 支持操作:建表、删表、ALTER 语句、INSERT/UPDATE/DELETE(无返回值)、创建索引等;
  • 使用场景:执行非查询类原生 SQL,无需获取执行结果;
  • 示例:同安卓

7.2.2 querySqlSync(sql : string, args : Array<string | number> | null) : ExecuteResult

  • 底层API querySqlSync(sql: string, bindArgs?: Array<ValueType>):ResultSet
  • 作用:根据指定SQL语句查询数据库中的数据;
  • 支持操作:SELECT 语句;
  • 使用场景:执行大部分SELECT查询语句;
  • 示例
const sql = `SELECT * FROM user WHERE age > ? AND name LIKE ?`
const args = ["20", "%张%"] 
const result = sqlite.querySqlSync(sql,args); 
// 该方法内部对返回结果只进行了简单的便利转化,所以复杂的联合查询结果是扁平化的json数据,需要用户自己处理数据结构
console.log(result)

// 返回结果:
{
  success: true, // true: 标识SQL语句执行成功  false: 标识SQL语句执行失败
  msg: '执行成功', // 当实行失败时,这里展示报错信息
  dataL: [
    ...
  ]
} 

8 特别感谢

  • 感谢豆包在开发过程中的大力支持,和在本文档书写过程中的贡献;

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率: