更新记录
2.3.5(2025-01-19) 下载此版本
新增事务管理代码
2.3.3(2025-01-19) 下载此版本
推送实例代码
2.3.2(2025-01-19) 下载此版本
更改项目结构
查看更多平台兼容性
Vue2 | Vue3 |
---|---|
√ | √ |
App | 快应用 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节小程序 | QQ小程序 |
---|---|---|---|---|---|---|
HBuilderX 3.8.12 app-vue | × | × | × | × | × | × |
钉钉小程序 | 快手小程序 | 飞书小程序 | 京东小程序 | 鸿蒙元服务 |
---|---|---|---|---|
× | × | × | × | × |
H5-Safari | Android Browser | 微信浏览器(Android) | QQ浏览器(Android) | Chrome | IE | Edge | Firefox | PC-Safari |
---|---|---|---|---|---|---|---|---|
× | × | × | × | × | × | × | × | × |
uniapp操作sqlite数据库
uniapp
操作sqlite
数据库的orm
框架,完全使用TS
编写。该框架模仿mybatisplus
风格,使用简单,业务层无需关心数据库操作,只需要调用相应的API
即可。数据库查询操作,考虑到API
封装的复杂度,暂时采用sql
原生脚本拼接。
sqlite
数据库是需要使用sql
脚本创建相应的数据表,但是当前组件中已经编写好自动创建表的代码,只需编写好实体,在实体上指定好注解,在 @/uni_modules/stars-UniTS-SQLite-ORM/components/dbOrm/db/TableInit
文件中指定实体即可,下面详细介绍。
在使用该组件时,推荐先下载实例看看。实例代码并没有封装在组件中。
一、使用案例
<template>
<view class="content">
<button @click="addUser">添加用户数据</button>
<button @click="selectUser">查询数据</button>
</view>
</template>
<script lang="ts">
import { User } from '@/pages/example/model/User';
import { UserServiceImpl } from '@/pages/example/service/UserServiceImpl';
const userService = new UserServiceImpl();
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
// this.addUser()
},
methods: {
// 添加数据
async addUser() {
try {
// 插入数据
const user = new User();
user.name = '张三';
user.age = Math.floor(Math.random() * (35 - 18 + 1)) + 18;
user.price = 235
await userService.insertUser(user);
console.log("数据添加成功");
// 根据主键查询数据
const userById = await userService.getUserById(1);
console.log('根据主键查询数据:', userById);
// 查询所有数据
const userList = await userService.getUsers();
console.log('查询所有数据:', userList);
// 根据条件查询数据
const userByCondition = await userService.getUsersByCondition("age > 18");
console.log('根据条件查询数据:', userByCondition);
// 分页查询数据
const page = 3;
const size = 10;
const userPage = await userService.getUsersByPage(page, size, "age > 18", "age ASC");
console.log('分页查询数据:', userPage);
console.log(userById);
// 更新数据
userById.name = '李四';
await userService.updateUser(userById);
// 根据主键删除数据
// await userService.deleteUserById(3);
// 根据条件删除数据
// await userService.deleteUserByCondition("age < 30");
} catch (error) {
console.error('An error occurred during database operation:', error);
}
},
// 查询数据
async selectUser() {
try {
const user = await userService.getUsersByCondition("age > 30 and (id <=5 and id >= 2)")
console.log(user);
} catch (error) {
console.error('An error occurred during database operation:', error);
}
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
二、数据实体封装
import { BaseModel } from '@/uni_modules/stars-UniTS-SQLite-ORM/components/stars-UniTS-SQLite-ORM/dbOrm/model/BaseModel';
import { PrimaryKey, NotNull, FieldType } from '@/uni_modules/stars-UniTS-SQLite-ORM/components/stars-UniTS-SQLite-ORM/dbOrm/annotation/Decorators';
import { FieldTypeEnum } from '@/uni_modules/stars-UniTS-SQLite-ORM/components/stars-UniTS-SQLite-ORM/dbOrm/enum/FieldTypeEnum';
/**
* 这个类的部分字段不符合user表,例如:用户是没有price字段,但是这个表是为了测试字段和注解等功能。
*/
export class User extends BaseModel {
@PrimaryKey()
@NotNull()
@FieldType({ field: 'id', type: FieldTypeEnum.INTEGER })
id : number;
@FieldType({ field: 'name', type: FieldTypeEnum.TEXT, length: 255 })
@NotNull()
name : string;
@FieldType({ field: 'age', type: FieldTypeEnum.INTEGER })
age : number;
@FieldType({ field: 'price', type: FieldTypeEnum.INTEGER })
price : number;
@FieldType({ field: 'description', type: FieldTypeEnum.TEXT, length: 255 })
description : string;
@FieldType({ field: 'createdDate', type: FieldTypeEnum.TEXT, length: 255 })
createdDate : Date;
}
注解详解
@PrimaryKey()
@PrimaryKey()
注解修饰的表示数据库的主键,只要是修饰主键的字段类型必须为 INTEGER
l类型,数据库的主键列默认是自增的,所以插入数据时就无需再给主键赋值。
@NotNull()
非空,@NotNull()
注解修饰的字段,添加数据时必须有数据,不能为空。
@FieldType
注解中有三个属性,field
指定数据库中的字段,type
字段类型,length
字段长度【可选】
例如:@FieldType({ field: 'name', type: FieldTypeEnum.TEXT, length: 255 })
三、业务实现
import { BaseModel } from '@/uni_modules/stars-UniTS-SQLite-ORM/components/stars-UniTS-SQLite-ORM/dbOrm/model/BaseModel';
import { PageModel } from '@/uni_modules/stars-UniTS-SQLite-ORM/components/stars-UniTS-SQLite-ORM/dbOrm/model/PageModel';
import { ISqliteService } from '@/uni_modules/stars-UniTS-SQLite-ORM/components/stars-UniTS-SQLite-ORM/dbOrm/service/ISqliteService';
import { SqliteServiceImpl } from '@/uni_modules/stars-UniTS-SQLite-ORM/components/stars-UniTS-SQLite-ORM/dbOrm/service/impl/SqliteServiceImpl';
import { User } from '../model/User';
export class UserServiceImpl {
// 创建实现类的实例
private sqliteService : ISqliteService<BaseModel>;
constructor() {
this.sqliteService = new SqliteServiceImpl<BaseModel>();
}
// 插入用户
async insertUser(user : User) : Promise<void> {
return await this.sqliteService.insert(user);
}
// 根据 ID 获取用户
async getUserById(id : number) : Promise<User> {
return await this.sqliteService.selectById(id, User);
}
// 获取所有用户
async getUsers() : Promise<User[]> {
return await this.sqliteService.selectAll(User);
}
// 根据条件获取用户
async getUsersByCondition(condition : string) : Promise<User[]> {
return await this.sqliteService.selectByCondition(condition, User);
}
/**
* 分页查询用户
*/
async getUsersByPage(page : number, size : number, condition ?: string, orderBy ?: string) : Promise<PageModel> {
return await this.sqliteService.selectByPage(page, size, condition, orderBy, User);
}
// 更新用户
async updateUser(user : User) : Promise<void> {
return await this.sqliteService.update(user);
}
// 根据 ID 删除用户
async deleteUserById(id : number) : Promise<void> {
return await this.sqliteService.deleteById(id, User);
}
// 根据条件删除用户
async deleteUserByCondition(condition : string) : Promise<void> {
return await this.sqliteService.deleteByCondition(condition, User);
}
}
考虑到前端操作数据库并不复杂,所以没有将数据操作层与业务完全拆封开。
四、配置说明
在 @/uni_modules/stars-sqlite-orm/components/stars-sqlite-orm/dbOrm/config/dbconfig
文件中编写了数据库的配置信息。
// 数据库信息配置
// 数据库名称
export const DB_NAME : string = 'user_db';
// 数据库的数据保存地址,如果这里配置了,那么就以这里的为准,否则以系统自动分配
export const DB_PATH : string = '';
// 关闭应用处理时间,单位:毫秒。就是用户关闭应用后,需要留多长时间来给业务处理,比如:200秒,那么用户点击关闭应用后,会留200秒来处理业务,200秒后,应用才会真正的关闭
export const DB_CLOSE_TIMEOUT : number = 200;
可能会更改的就是数据库名称 DB_NAME
。
五、App.vue文件配置
在App.vue
文件中需要指定 created
事件处理。处理的业务主要是对数据库的打开和关闭操作。当应用启动时,会自动打开数据库。当应用关闭时,会关闭数据库后再关闭应用。注意:应用是彻底关闭时才会关闭数据库,当应用隐藏到后台时,不会关闭数据库。特别注意:当应用并没有点击退出按钮,而是直接杀死应用进程,或者应用隐藏到后台,自动杀死进程的方式,数据库是不会关闭的。
<template>
<div>
<!-- 这里可以添加你的页面内容 -->
</div>
</template>
<script lang="ts">
import { appOpen } from '@/uni_modules/stars-UniTS-SQLite-ORM/components/stars-UniTS-SQLite-ORM/app/application.ts';
export default {
data() {
return {
};
},
created() {
// 应用打开和关闭事件
appOpen()
},
onLaunch() {
console.log("应用创建");
},
onHide() {
console.log("应用正在隐藏");
},
onShow() {
console.log("应用正在显示");
},
methods: {
}
};
</script>
六、自动创建表
在 @/uni_modules/stars-UniTS-SQLite-ORM/components/dbOrm/db/TableInit
文件中配置实体,应用启动时会自动判断数据表是否存在,如果数据表不存在则自动创建。
/**
* 初始化表
*/
public static tableInit() : void {
const createProductTableSQL = CrateTable.generateCreateTableSQL(User);
console.log(createProductTableSQL);
executeSql(DB_NAME, createProductTableSQL);
executeSql(DB_NAME, CrateTable.generateCreateTableSQL(实体名即可));
console.log("创建表成功:", User.name.toLowerCase());
}
七、tsconfig.json
文件配置
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"exclude": [
"node_modules",
"unpackage",
"dist"
]
}
-
"compilerOptions": {... }
:包含了 TypeScript 编译器的各种选项,是整个配置的核心部分。
"target": "esnext"
:指定编译后的 JavaScript 代码的目标版本。根据你的项目需求,可以保持为esnext
或调整为其他目标版本,如es5
或es6
。"module": "esnext"
:指定模块系统,esnext
表示使用最新的模块系统,可根据实际情况调整。"strict": true
:启用严格模式,这有助于发现更多潜在的错误,建议保持为true
。"moduleResolution": "node"
:使用 Node.js 的模块解析策略,对于大多数项目是适用的。"esModuleInterop": true
:允许在 CommonJS 和 ES 模块之间进行互操作,在使用第三方模块时可能会用到,建议保留。"allowSyntheticDefaultImports": true
:允许从没有默认导出的模块中导入默认导出,在使用一些库时可能会需要,建议保留。"sourceMap": true
:生成源映射文件,方便调试,在开发阶段比较有用,可根据情况决定是否保留。"experimentalDecorators": true
:因为你使用了装饰器(如@Transactional
),此选项必须设置为true
,以便编译器识别和处理装饰器。"emitDecoratorMetadata": true
:如果你使用的装饰器需要元数据,这个选项也应该设置为true
,对于使用装饰器的项目很重要,建议保留。
可根据项目调整的配置项:
"baseUrl": "."
:指定基本目录,可根据项目结构调整。"types": ["uniapp"]
:指定引入的类型声明文件,如果你使用了 UniApp 相关的类型声明,可以保留。"paths": { "@/*": ["./src/*"] }
:自定义模块路径映射,方便导入模块,根据项目结构和个人喜好可调整或保留。
关于 include
和 exclude
:
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "typings/**/*.d.ts", "types/**/*.d.ts"]
:指定需要编译的文件,可根据项目文件的位置和扩展名进行调整。确保包含了你的*.ts
文件,尤其是使用装饰器的文件。"exclude": ["node_modules", "unpackage", "dist"]
:排除不需要编译的目录,可根据项目结构进行调整,一般不需要修改。
总结:
- 对于使用装饰器的项目,
"experimentalDecorators": true
和"emitDecoratorMetadata": true
是不可或缺的,以确保 TypeScript 编译器能正确处理装饰器。 - 其他配置项可根据项目的具体需求和结构进行调整,但
strict
模式、moduleResolution
和esModuleInterop
等通常建议保留,以保证代码质量和模块的正常导入。
注意事项:
- 在修改
tsconfig.json
时,确保重新编译项目,以便新的配置生效。 - 不同的配置项可能会影响项目的构建和运行,因此在调整时需要谨慎,特别是在修改
target
和module
等关键选项时。
以下是一个简化但保留关键部分的 tsconfig.json
示例。
八、事务使用
直接在业务上使用 @Transactional
注解即可.
- 范例
// 事务测试
@Transactional
transactionalTest(user : User) : void {
console.log("处理业务逻辑开始");
this.sqliteService.insert(user);
let users = new User();
users.id = 1;
users.name = '这是更改后的名字';
this.sqliteService.update(users);
this.sqliteService.deleteById(2, User);
// 制造一个异常
this.sqliteService.update(null);
throw new Error("制造一个异常");
console.log("处理业务逻辑结束");
}