前一篇文章中,我们简要介绍了Vonajs的核心功能。在这里,我们再来看看Vonajs提供的Model能力,可以让我们用简洁、优雅的代码全方位操作数据库,比如,动态分表、软删除、多租户、动态数据源、二级缓存,等等

创建Model

比如,我们在模块 demo-student 中创建一个 Model: student

1. Cli命令

$ vona :create:bean model student --module=demo-student

2. 菜单命令

使用菜单命令可以显著提升开发体验,减少心智负担

右键菜单 - [模块路径]: `Vona Create/Model`

Model定义

import { BeanModelBase, Model } from 'vona-module-a-database';
import { EntityStudent } from '../entity/student.ts'; @Model({ entity: EntityStudent })
export class ModelStudent extends BeanModelBase<EntityStudent> {}
  • 继承自 BeanModelBase 基类
  • 使用 Model 装饰器
  • 设置对应的 entity

使用Model

在 Vona 中使用 Model,支持依赖注入依赖查找。推荐使用依赖查找,因为依赖查找可以让代码更加简洁、直观

1. 本模块查找

class ServiceStudent {
async findAll(): Promise<EntityStudent[]> {
return await this.scope.model.student.select();
}
}
  • this.scope:当前模块的scope对象
  • this.scope.model.student:从scope中直接获取student model实例

2. 跨模块查找

class ServiceStudent {
async findAll(): Promise<EntityStudent[]> {
return await this.$scope.demoStudent.model.student.select();
}
}
  • this.$scope.demoStudent:获取指定模块的scope对象
  • this.$scope.demoStudent.model.student:从scope中直接获取student model实例

CRUD

在这里,我们仅介绍基本的 CRUD 操作

1. Create

class ServiceStudent {
async create(student: DtoStudentCreate): Promise<EntityStudent> {
return await this.scope.model.student.insert(student);
}
}

2. Read

class ServiceStudent {
async findAll(): Promise<EntityStudent[]> {
return await this.scope.model.student.select();
} async findOne(id: TableIdentity): Promise<EntityStudent | undefined> {
return await this.scope.model.student.get({ id });
}
}
  • id: 类型为TableIdentity,支持numberbignumber两种字段类型

3. Update

class ServiceStudent {
async update(id: TableIdentity, student: DtoStudentUpdate) {
return await this.scope.model.student.update({
...student,
id,
});
}
}

4. Delete

class ServiceStudent {
async remove(id: TableIdentity) {
return await this.scope.model.student.delete({ id });
}
}

Knex Query Builder

Vona Model 底层使用的是knex。因此,也支持 knex 提供的Query Builder

1. builder

调用 model 的 builder 方法获取 knex query builder 的实例

class ServiceStudent {
async findAll(): Promise<EntityStudent[]> {
return await this.scope.model.student.builder().where('name', 'tom').orderBy('name');
}
}

2. builderSelect

builderSelect 方法也是获取 knex query builder 的实例,与 builder 不同的是,builderSelect 支持软删除多实例/多租户

class ServiceStudent {
async findAll(): Promise<EntityStudent[]> {
return await this.scope.model.student.builderSelect().where('name', 'tom').orderBy('name');
}
}

Model Options

名称 说明
entity model对应的entity
table model对应的表名
disableDeleted 是否禁用软删除,默认为false
disableInstance 是否禁用多实例/多租户,默认为false
clientName 指定数据源名称
cacheOptions 配置缓存参数,默认启用基于redis的缓存
  • table:

    • 如果为空,则从 entity 获取表名
    • 可以指定函数,实现动态分表的能力

App config配置

如果通过@Model装饰器设置的Model options不符合业务需要,我们还可以在 App config 中修改 Model options的配置。比如,设置缓存参数

src/backend/config/config/config.dev.ts

// onions
config.onions = {
model: {
'demo-student:student': {
disableDeleted: true, // 禁用软删除
disableInstance: true, // 禁用多实例/多租户
cacheOptions: false, // 禁用缓存
clientName: 'mysql', // 使用数据源:mysql
},
},
};
  • demo-student:student:模块名称+model名称

动态分表

Model 支持动态分表的能力。比如,我们对 Order 进行分表处理,将每天的订单存入order_YYYYMMDD格式的数据表中

@Model({ table: (ctx: VonaContext, defaultTable: keyof ITableRecord) => {
return `${defaultTable}_${moment().format('YYYYMMDD')}`;
} })
class ModelOrder {}
  • ctx: 可以基于当前请求的上下文来动态生成表名
  • defaultTable: 默认的表名,从entity中获取

软删除, 多实例/多租户

Model 默认自动启用软删除,当删除一条数据时,并不进行物理删除,而是设置字段 deleted 的值为 true

Model 默认支持多实例/多租户。对数据进行 CRUD 操作时,自动从 Request 上下文获取实例Id,并传入 sql 语句中

比如,执行model.student.select(),那么生成的 sql 如下:

select "demoStudent"."id" from "demoStudent"
where "demoStudent"."iid" = 1 and "demoStudent"."deleted" = false
  • iid:实例 Id
  • deleted:软删除

临时禁用软删除

我们也可以在执行 model 方法时临时指定软删除参数

class ServiceStudent {
async findAll(): Promise<EntityStudent[]> {
return await this.scope.model.student.select({}, { disableDeleted: true });
}
}

数据源

Vona 支持多数据库多数据源。可以针对任何一个数据源调用 Model 的方法

1. 默认数据源

在默认情况下,Model 使用的是系统设置的缺省数据源

env/.env

DATABASE_DEFAULT_CLIENT = 'pg' # pg/mysql
  • 系统当前默认使用的是pg数据源

2. 静态数据源

  • 在 Model options 中指定数据源
@Model({ clientName: 'mysql' })
class ModelBook {}
  • clientName:需要指定的数据源名称

  • 在 App config 中指定数据源

src/backend/config/config/config.dev.ts

// onions
config.onions = {
model: {
'demo-student:student': {
clientName: 'mysql', // 使用数据源:mysql
},
},
};

3. 动态数据源

我们还可以在代码中动态指定数据源

class ServiceStudent {
async findAll(): Promise<EntityStudent[]> {
const modelMysql = this.scope.model.student.newInstance('mysql');
return await modelMysql.select();
}
}
  • newInstance: 传入数据源名称,既可创建新的model实例

缓存

Vona Model 默认启用了缓存,从而使系统在默认情况下就具备非常高的性能

Model 支持二级缓存/mem缓存/redis缓存。默认使用的是redis缓存。因为redis缓存可以在分布式场景下保持数据的一致性,而mem缓存在分布式场景下同步数据有延时。如果业务数据变更不频繁,可以使用mem缓存或者二级缓存,从而获得更高性能

如何设置缓存配置:

1. 禁用缓存

@Model({ cacheOptions: false })
class ModelStudent {}

2. 在 Model options 中配置缓存

@Model({ cacheOptions: {
mode: 'all', // all/mem/redis
mem: {
max: 500,
ttl: 5 * 1000, // 5s
},
redis: {
ttl: 5 * 1000, // 5s
},
} })
class ModelStudent {}
  • mode:缓存模式:支持二级缓存/mem缓存/redis缓存
  • mem:mem缓存配置
  • redis:redis缓存配置

3. 在 App config 中配置缓存

我们也可以在App config中根据业务需要修改Model的缓存配置

src/backend/config/config/config.dev.ts

// onions
config.onions = {
model: {
'demo-student:student': {
cacheOptions: {
mode: 'all', // all/mem/redis
mem: {
max: 500,
ttl: 5 * 1000, // 5s
},
redis: {
ttl: 5 * 1000, // 5s
},
}
},
},
};

结语

Vonajs已开源:https://github.com/vonajs/vona

Vonajs作者正在B站直播撰写技术文档,工作日每晚8:30,欢迎围观:濮水代码

开发一个功能完备的Nodejs框架固然费时费力,但是撰写技术文档更加费尽心思。写文档的过程同时也是再次梳理思路的过程,即便是围观,也有利于加深对框架设计的理解,探索不一样的架构设计路径。目前已完成部分文档,更多精彩正在逐步展开,欢迎参与

使用这个model操作数据库,一爽到底的更多相关文章

  1. Qt的Model/View Framework解析(数据是从真正的“肉(raw)”里取得,Model提供肉,所以读写文件、操作数据库、网络通讯等一系列与数据打交道的工作就在model中做了)

    最近在看Qt的Model/View Framework,在网上搜了搜,好像中文的除了几篇翻译没有什么有价值的文章.E文的除了Qt的官方介绍,其它文章也很少.看到一个老外在blog中写道Model/Vi ...

  2. Django框架中的model(操作数据库)

    什么是ORM ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复 ...

  3. Django进阶Model篇—数据库操作(ORM)

    一.数据库配置 django 默认支持sqlite.mysql.oracle.postgresql数据库,像db2和sqlserver之类的数据库需要第三方的支持,具体详见https://docs.d ...

  4. Django入门:操作数据库(Model)

    Django-Model操作数据库(增删改查.连表结构) 一.数据库操作 1.创建model表         基本结构 1 2 3 4 5 6 from django.db import model ...

  5. Django之Model操作

    Django之Model操作 本节内容 字段 字段参数 元信息 多表关系及参数 ORM操作 1. 字段 字段列表 AutoField(Field) - int自增列,必须填入参数 primary_ke ...

  6. Asp.Net MVC 自定义的MVC框架(非EF操作数据库)

    一些废话:在北京辞职回家不知不觉中已经半年多了,这半年中有过很多的彷徨,困惑,还有些小小难受.半年时间算是我人生以来遇到过的最困苦的时候.理想的工作跟我擦肩而过,驾照也没有考过,年后这一改革...,毕 ...

  7. Java数据库连接——JDBC基础知识(操作数据库:增删改查)

    一.JDBC简介 JDBC是连接java应用程序和数据库之间的桥梁. 什么是JDBC? Java语言访问数据库的一种规范,是一套API. JDBC (Java Database Connectivit ...

  8. QT 操作数据库

    整理一下 QT 操作数据库的一些要点,以备以后的查询学习(主要是操作 mysql ). 首先,要查询相关的驱动是否已经装好了,可以用以下的程序进行验证: #include <QtCore/QCo ...

  9. Python之路【第二十二篇】:Django之Model操作

    Django之Model操作   一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bi ...

  10. Day19 Django之Form表单验证、CSRF、Cookie、Session和Model操作

    一.Form表单验证 用于做用户提交数据的验证1.自定义规则 a.自定义规则(类,字段名==html中的name值)b.数据提交-规则进行匹配代码如下: """day19 ...

随机推荐

  1. 【SpringMVC】RESTful CRUD

    RESTful CRUD REST:即 Representational State Transfer.(资源)表现层状态转化.是目前最流行的一种互联网软件架构.它结构清晰.符合标准.易于理解.扩展方 ...

  2. 在 .NET 中 使用 ANTLR4

    前言 本文将介绍如何在 .NET 中使用 ANTLR4 构建语法分析器.由于篇幅限制,本文不会深入讲解 ANTLR4 的语法规则,相关内容可参考 ANTLR4 的官方文档或其他资料.本文将涵盖以下内容 ...

  3. Postwoman教程

    1.安装 打开git或cmder,输入如下命令: cd d:/GitDemo/ git clone https://github.com/liyasthomas/postwoman cd postwo ...

  4. Rocketmq 如何处理消息积压 ?

    一.消息积压发现 1.Console入口 A.延迟数量(Delay) 消息积压数量,即当前Topic还剩下多少消息未处理,该值越大,表示积压的消息越多 B.最后消费时间(LastConsumeTime ...

  5. 基于注解创建bean对象和注入方式

    一.配置spring核心配置文件ApplicationContext.xml,添加扫描包 二.注解创建bean对象 三.注入方法

  6. Web前端入门第 34 问:CSS 常见布局

    Web 网页中,所有元素都是盒模型构成的,一个大盒子套一个或者多个小盒子,再用更大的盒子把大盒子给圈起来,这就构成了基本的 HTML 结构,再利用 CSS 把盒子装修得好看一些,最后把它放在正确位置, ...

  7. jmeter:结合while控制器实现性能测试

    一.场景 1.导入时,导入操作的用户数比较少,但是单次导入的数据量较大 2.导入文件一共有三步操作,上传-验证-导入,执行完当前操作才可以执行下一步操作. 2.导入时,即使导入数据量较大,导入操作需要 ...

  8. krpano场景拖动时拖动惯性消失的问题

    问题背景:在写一个基于krpano的全景项目时突然发现场景拖动时拖动惯性消失了.查看官方文档,检查和控制相关的control标签的参数没有问题,并且也一直没有修改过. 排查过程:推测为某插件调用了相关 ...

  9. P7404题解

    分析题意: 题意就是让前半段序列呈上升趋势,后半段呈下降趋势. 解题方法: 考虑差分出序列的高度. xix_ixi​ 表示以 iii 为 kkk 的前半段需增加量. yiy_iyi​ 表示以 i−1i ...

  10. C# 线程基础——用户模式、内核模式

    C# 线程基础--用户模式.内核模式 参照:用户模式和内核模式 - Windows drivers | Microsoft Docs 基础概念 运行 Windows 的计算机中的处理器有两个不同模式: ...