写点什么

Nodejs 相关 ORM 框架分析

作者:coder2028
  • 2022-10-26
    浙江
  • 本文字数:4418 字

    阅读完需:约 14 分钟

概述

写这篇 blog 的原因,想找个 node 的 ORM 框架用用,确很难找到一篇对比分析这些 ORM 框架的文章,唯一找到了一篇,居然是通过 star 数来论英雄,我觉着很难服众,于是就找几个看看。后来又不想分析,因为我发现 node 这种野蛮生长,滋生这些 ORM 轮子比比皆是,远比我想象的多;后来又觉着可以写,作为一个 java 出身业余研究 node 的就想通过 java 的 ORM 框架来洞悉 node 这群 ORM 框架的是非曲直,于是挑了几个框架小扯一篇。

ORM 框架

ORM 框架:Object Relational Mapping,对象-关系-映射,所以说 ORM 框架就是用面向对象的方式和目前的关系型数据库做匹配,java 开发者目前主流的 hibernate、mybatis 很熟悉了,JDBC 原始驱动的方式想必也不在成为主流了。下面介绍几款 node 的 ORM 框架,介绍之前先介绍 ORM 的两种模式:


Active Record 模式:活动记录模式,领域模型模式一个模型类对应关系型数据库中的一个表,模型类的一个实例对应表中的一行记录。这个不难理解,比较简单,但是不够灵活,再看另一种模式,比较一下


Data Mapper 模式:数据映射模式,领域模型对象和数据表是松耦合关系,只进行业务逻辑的处理,和数据层解耦。需要一个实体管理器来将模型和持久化层做对应,这样一来,灵活性就高,当然复杂性也增加了。


所以说,Data Mapper 模式对业务代码干预少,Active Record 模式直接在对象上 CRUD,代码编写也更方便,这就像 hibernate 和 mybatis 两种框架,如果想深入研究,可以了解一下


有这么一句话很认同,ActiveRecord 更加适合快速开发成型的短期简单项目,而 DataMapper 更加适合长线开发,保持业务逻辑与数据存储独立的复杂项目。除此之外,技术选型还要考虑其他因素,比如项目历史背景等等。

TypeORM

TypeORM 是一个 ORM 框架,详细介绍见 TypeORM 官方介绍,TypeORM 也借鉴了 hibernate,所以你会发现它特别熟悉,尤其是装饰类的方式。


闲话少说,直接用 CLI 命令快速构建项目


npm install typeorm -g
复制代码


创建项目


typeorm init --name MyProject --database mysql
复制代码


name 是项目的名称,database 是将使用的数据库,TypeORM 支持多种数据库。


生成文档结构


MyProject├── src              // TypeScript 代码│   ├── entity       // 存储实体(数据库模型)的位置│   │   └── User.ts  // 示例 entity│   ├── migration    // 存储迁移的目录│   └── index.ts     // 程序执行主文件├── .gitignore       // gitignore文件├── ormconfig.json   // ORM和数据库连接配置├── package.json     // node module 依赖├── README.md        // 简单的 readme 文件└── tsconfig.json    // TypeScript 编译选项
复制代码


修改 ormconfig.json 数据库配置文件,直接运行就可以了


npm start
复制代码


看一下实体 model,user 类


import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";@Entity()export class User {​    @PrimaryGeneratedColumn()​    id: number;
​ @Column()​ firstName: string;
​ @Column()​ lastName: string;
​ @Column()​ age: number;}
复制代码


CRUD 操作:逻辑层


import "reflect-metadata";import {createConnection} from "typeorm";import {User} from "./entity/User";
createConnection().then(async connection => {​ console.log("Inserting a new user into the database...");​ const user = new User();​ user.firstName = "Timber";​ user.lastName = "Saw";​ user.age = 25;​ await connection.manager.save(user);​ console.log("Saved a new user with id: " + user.id);​ console.log("Loading users from the database...");​ const users = await connection.manager.find(User);​ console.log("Loaded users: ", users);​ console.log("Here you can setup and run express/koa/any other framework.");}).catch(error => console.log(error));
复制代码


所以,TypeORM 的方式很像 hibernate 的方式,虽然 es6 中就已经有装饰器类似 java 的注解的功能了,但是还是和装饰器有所区别,因为 TypeORM 采用的是 TypeScript 的方式,TypeScript 是 JavaScript 的一个超集,TypeScript 采用类型注解方式,虽然支持 es6 的标准,但是有些语法还是需要了解,这也或多或少增加了一些选择难度。

Sequelize

这个被 star 数最多了一个 ORM 框架,官方居然不给中文文档,找个 CLI 命令快速构建也没有,也没找到个合适轮子,只能自己搭了,也不是少了轮子就不能活了。不过 Sequelize 的官网文档看着很顺眼,不得不称赞一下,需要注意的一点 Sequelize v5 版本发生了比较大的变化,这里我以最新版本 v5 版本为主,老版本可以自己看看下官方文档。Sequelize v5


安装 npm 包


$ npm install --save sequelize$ npm install --save mysql2
复制代码


数据库的配置文件 config.js


module.exports = {​    database: {​        dbName: 'TEST',​        host: 'localhost',​        port: 3306,​        user: 'root',​        password: '123456'​    }}
复制代码


构建数据库访问公共文件 db.js


const Sequelize = require('sequelize')const {​    dbName,​    host,​    port,​    user,​    password} = require('../config').database
const sequelize = new Sequelize(dbName, user, password, {​ dialect: 'mysql',​ host,​ port,​ logging: true,​ timezone: '+08:00',​ define: {​ // create_time && update_time​ timestamps: true,​ // delete_time​ paranoid: true,​ createdAt: 'created_at',​ updatedAt: 'updated_at',​ deletedAt: 'deleted_at',​ // 把驼峰命名转换为下划线​ underscored: true,​ scopes: {​ bh: {​ attributes: {​ exclude: ['password', 'updated_at', 'deleted_at', 'created_at']​ }​ },​ iv: {​ attributes: {​ exclude: ['content', 'password', 'updated_at', 'deleted_at']​ }​ }​ }​ }})// 创建模型sequelize.sync({​ force: false})module.exports = {​ sequelize}
复制代码


model


const {Sequelize, Model} = require('sequelize')const {db} = require('../../db')
class User extends Model {}User.init({ // attributes firstName: { type: Sequelize.STRING, allowNull: false }, lastName: { type: Sequelize.STRING // allowNull defaults to true }}, { db, modelName: 'user' // options});
复制代码


还有一种写法,兼容老版本,不推荐


const User = db.define('user', {    // attributes    firstName: {        type: Sequelize.STRING,        allowNull: false    },    lastName: {        type: Sequelize.STRING        // allowNull defaults to true    }}, {    // options});
复制代码


这种实际上是 sequelize.define 内部调用了 model.init,但是老版本是没有第一种写法的。


此外需要知道的是,sequelize 还默认为每个模型定义字段 id(主键)、createdat 和 updatedat,也可以进行设置。


我们的 db.js 文件里面配置了,不自动创建模型,也就是自动创建数据表,关闭是有原因的,因为如果表存在会先 drop 然后再创建,这种操作本身就很可怕的


参考 nodejs 进阶视频讲解:进入学习


// 创建模型sequelize.sync({    force: false})
复制代码


单个模型也可以配置,切记这种操作很危险,尤其是生成环境


// Note: using `force: true` will drop the table if it already existsUser.sync({ force: true }).then(() => {    // Now the `users` table in the database corresponds to the model definition    return User.create({        firstName: 'John',        lastName: 'Hancock'    });});
复制代码


CRUD 操作:然后看一下逻辑层,就非常简单了,直接使用 ES7 async/await即可


// Find all usersUser.findAll().then(users => {    console.log("All users:", JSON.stringify(users, null, 4));});// Create a new userUser.create({ firstName: "Jane", lastName: "Doe" }).then(jane => {    console.log("Jane's auto-generated ID:", jane.id);});// Delete everyone named "Jane"User.destroy({    where: {        firstName: "Jane"    }}).then(() => {    console.log("Done");});// Change everyone without a last name to "Doe"User.update({ lastName: "Doe" }, {    where: {        lastName: null    }}).then(() => {    console.log("Done");});
复制代码


由此来看,没有 typeorm 装饰类的方式看着顺眼,但是整体构造也容易上手,操作简单,容易理解,看官网文档,功能覆盖强大,typeorm 用户反馈使用问题比 Sequelize 要多,后期用到再做比较。

ORM2

ORM2 貌似没有正了八经的官网,所以看起来就特别麻烦,但是可以看一下 github 介绍 node-orm2,只支持四种数据库 MySQL、PostgreSQL、Amazon Redshift、SQLite,这个我没写 demo,直接分析一下


安装


npm install orm
复制代码


数据库连接


var orm = require("orm");orm.connect("mysql://username:password@host/database",     function (err, db) {    // ...里面一些参数不详细写了});
复制代码


model


var Person = db.define('person', {    name: String,    surname: String,    age: String,    male: boolean}, {    identityCache : true});
复制代码


CRUD 操作


Person.create([    {        name: "John",        surname: "Doe",        age: 25,        male: true    },    {        name: "Liza",        surname: "Kollan",        age: 19,        male: false    }], function (err, items) {    // err - description of the error or null    // items - array of inserted items});
复制代码


Person.get(1, function (err, John) {    John.name = "Joe";    John.surname = "Doe";    John.save(function (err) {        console.log("saved!");    });//保存    Person.find({ surname: "Doe" }).remove(function (err) {      // Does gone..    });//删除});
复制代码


Person.find({    name: "admin"})    .limit(3)    .offset(2)//跳过    .only("name", "age")//返回字段    .run(function(err, data) {
});
复制代码


所以,准确应该是 node-orm2,写法和 sequelize 类似,但是文档确实不行,数据库支持也少,很难想象后续的可维护性。

其它

  • bookshelf(这个用的也挺多)

  • persistencejs

  • waterline

  • mongoose

  • node-mysql

  • knex


用户头像

coder2028

关注

还未添加个人签名 2022-09-08 加入

还未添加个人简介

评论

发布
暂无评论
Nodejs相关ORM框架分析_node.js_coder2028_InfoQ写作社区