6.ORM框架-Sequelize

2,329 阅读6分钟

介绍

对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中 概述

Sequelize 是一个基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server. 它具有强大的事务支持, 关联关系, 预读和延迟加载,读取复制等功能.

为什么选择它?

Node.js 中连接数据库需要自己建立并管理连接,操作繁琐,还需要自己编写 sql 语句。简单的项目可能还行,当项目设计的东西比较复杂,表比较多的时候,对于 sql 语句的编写就比较耗费精力。

在 Java、C# 等语言中都已经有轻量级的数据库框架或者解决方案了。在 Node.js 中可以使用 Sequelize ,它是一个很成熟的框架,在速度和性能上也非常有优势。而且关键在于,开发时只需要管理对象的创建、查询方法的调用等即可,极少需要编写 sql 语句。这样一来不仅省去了复杂的 sql 语句维护,同时也避免了因 sql 语句而引起的不必要的bug。

安装

cnpm i sequelize mysql2 -S

基本使用

连接数据库

//导入 sequelize
const Sequelize = require('sequelize');

//连接数据库
//参数:数据库  用户名  密码    配置
const sequelize = new Sequelize('db1', 'root', '******', {
    host: 'localhost', //主机地址
    dialect: 'mysql', //语言
})

测试连接

//测试连接
async function test() {
    try {
        await sequelize.authenticate();
        console.log('Connection has been established successfully.');
    } catch (error) {
        console.error('Unable to connect to the database:', error);
    }
}

test();

模型同步

通过调用一个异步函数(返回一个Promise)model.sync(options). 通过此调用,Sequelize 将自动对数据库执行 SQL 查询.

  • Books.sync() - 如果表不存在,则创建该表(如果已经存在,则不执行任何操作)
  • Books.sync({ force: true }) - 将创建表,如果表已经存在,则将其首先删除
  • Books.sync({ alter: true }) - 这将检查数据库中表的当前状态(它具有哪些列,它们的数据类型等),然后在表中进行必要的更改以使其与模型匹配

创建模型(表)并添加到数据库

//定义模型
const Books = sequelize.define('books' /* 自定义表名 */ , {
    // 定义表中的字段,对象中的属性
    id: {
        type: Sequelize.INTEGER, //定义数据类型
        primaryKey: true, //设置主键
        autoIncrement: true, //设置自动增长
        comment: '自增id', //添加描述
    },
    name: {
        type: Sequelize.STRING,
        allowNull: false, //是否允许为空,默认为true
    },
    price: {
        type: Sequelize.FLOAT,
        allowNull: false,
    },
    count: {
        type: Sequelize.INTEGER,
        defaultValue: 0, //设置默认值
    }
}, {
    // 其他模型参数
    timestamps: false, //禁用时间戳,去掉createdAt和updatedAt字段,默认为true
    freezeTableName: true, //表名冻结,Model对应的表名将与定义的'books'相同,默认为true
});

//模型同步,迁移模型映射到数据库
Books.sync({
    force: true //将创建表,如果表已经存在,则将其首先删除
})

一次同步所有模型

可以使用 sequelize.sync() 自动同步所有模型.

await sequelize.sync({ force: true });
console.log("所有模型均已成功同步.");

更多数据类型

字符串

Sequelize.STRING             // VARCHAR(255),默认长度255
Sequelize.STRING(1234)       // VARCHAR(1234),指定长度的字符串
Sequelize.STRING.BINARY      // VARCHAR BINARY
Sequelize.TEXT               // TEXT,文本字符串
Sequelize.TEXT('tiny')       // TINYTEXT,小文本字符串

布尔

Sequelize.BOOLEAN            // TINYINT(1),小int类型,长度为1(0,1)

数字

Sequelize.INTEGER            // INTEGER,int类型
Sequelize.BIGINT             // BIGINT,更大的int类型
Sequelize.BIGINT(11)         // BIGINT(11),指定长度的BIGINT

Sequelize.FLOAT              // FLOAT,浮点类型
Sequelize.FLOAT(11)          // FLOAT(11),指定长度的浮点类型
Sequelize.FLOAT(11, 10)      // FLOAT(11,10),指定长度和小数点后的位数

Sequelize.DOUBLE             // DOUBLE
Sequelize.DOUBLE(11)         // DOUBLE(11)
Sequelize.DOUBLE(11, 10)     // DOUBLE(11,10)

Sequelize.DECIMAL            // DECIMAL,更准确的小数点类型
Sequelize.DECIMAL(10, 2)     // DECIMAL(10,2),指定长度和小数点后的位数

日期

Sequelize.DATE       // DATETIME 适用于 mysql / sqlite, 带时区的TIMESTAMP 适用于 postgres
Sequelize.DATE(6)    // DATETIME(6) 适用于 mysql 5.6.4+. 支持6位精度的小数秒
Sequelize.DATEONLY   // 不带时间的 DATE,仅日期部分

枚举

Sequelize.ENUM('value 1','value 2','value 3')   //枚举类型,从 value 1、value 2、value 3中取

JSON

Sequelize.JSON       //适用于 mysql 5.7.8+ ,JSON类型

删除表

删除与模型相关的表:

await Books.drop();
console.log("用户表已删除!");

删除所有表:

await sequelize.drop();
console.log("所有表已删除!");

增删查改

插入一条数据使用create({}).

Books.sync({
    force: true //将创建表,如果表已经存在,则将其首先删除
}).then(() => {
    //插入一条数据使用 create({})
    return Books.create({
        name: 'JavaScript编程',
        price: '36.6',
        count: 14
    })
})

插入多条数据使用bulkCreate([{},{}]).

Books.sync({
    force: true //将创建表,如果表已经存在,则将其首先删除
}).then(() => {
    //插入多条数据使用 bulkCreate([{},{}])
    return Books.bulkCreate([{
        name: 'JavaScript编程',
        price: 36.6,
        count: 36
    }, {
        name: 'Vue实战开发',
        price: 99.9,
        count: 64
    }, {
        name: 'React实战开发',
        price: 128.6,
        count: 87
    }, {
        name: 'Node.js实战',
        price: 136.2,
        count: 59
    }])
})

查询所有数据使用Books.findAll().

Books.findAll().then(books => {
    console.log('all books', JSON.stringify(books, null, 4)); //使用四个空格缩进
    //计算总价格
    console.log(books[0].price*50);
})

查询一条数据使用Books.findOne().

//查询一条数据
Books.findOne().then(books => {
    console.log(JSON.stringify(books, null, 4));
})

默认查询第1条数据,可在findOne()中指定查询的条件

Books.findOne({
    where: {
        id: 2
    }
}).then(books => {
    console.log(JSON.stringify(books, null, 4));
})

更多的查询操作

具体参考:sequelize模型查询

//导入 Op
const Op = Sequelize.Op;

Books.findAll({
    //SELECT `name`, `price` FROM `books` AS `books` WHERE 
    //`books`.`price` > '40' ORDER BY `books`.`id` DESC LIMIT 2;
    where: {
        price: {
            //价格大于40
            //SELECT `id`, `name`, `price`, `count` FROM `books` AS `books` 
            //WHERE `books`.`price` > '40';
            [Op.gt]: 40,
        },
    },
    order: [
        ['id', 'DESC'], //按id,倒序
    ],
    limit: 2, //返回的个数
    // attributes: ['name', 'price'], //查询特定属性,只要 name 和 price
    attributes: {
        exclude: ['id', 'name'] //查询特定属性,不包含 id 和 name
    },
}).then(books => {
    console.log('all books', JSON.stringify(books, null, 4)); //使用四个空格缩进
})

聚合函数

//count 方法仅计算数据库中元素出现的次数.
Books.count('id').then(counts => console.log(counts));
//max 方法获取数据库中元素的最大值
Books.max('price').then(maxPrice => console.log(maxPrice));
//min 方法获取数据库中元素的最小值
Books.min('price').then(minPrice => console.log(minPrice));
//sum 方法获取数据库中元素的总和
Books.sum('count').then(sum => console.log(sum));

扩展

有时候在获取之后可能还需要进行一些其他的操作,比如说:计算总价格 books[0].price*购买的数量,但是每次都这样操作,不方便,可以考虑扩展一些方法。

实例扩展

在Books的原型上扩展一个计算总价格的方法

//实例扩展
Books.prototype.totalPrice = function (count) {
    return this.price * count;
}

Books.findAll().then(books => {
    console.log('all books', JSON.stringify(books, null, 4)); //使用四个空格缩进
    //直接调用原型上的方法即可
    console.log(books[0].totalPrice(50));
})

模型扩展

直接在Books上扩展方法

//模型扩展
Books.classify = function (name) {
    const XHPublisher = ['JavaScript编程', 'Node.js实战'];
    return XHPublisher.includes(name) ? '新华出版社' : '其他出版社';
}

const arr = ['React实战开发', 'JavaScript编程', 'Vue实战开发'];
arr.forEach(item => {
    //获取每一本书的出版社
    console.log(Books.classify(item));
})

//更新
Books.update({
    //UPDATE `books` SET `price`=? WHERE `id` = ?
    //要修改的值
    price: 50
}, {
    //条件
    where: {
        id: 1
    }
})

//删除
Books.destroy({
    //条件
    where: {
        id: 4
    }
})