【koa + vue + es6 + node】全家桶前后端分离项目实战(3)?

530 阅读6分钟

前面2篇文章分别对这个项目的项目结构、插件和开发前的准备做了一个大概的介绍。然后第二篇文章讲了一下koa是什么东西,我们能够依赖koa做一些什么事情。如果不清楚整个项目的大致方向,可以移步这里;如果不太清除koa怎么使用,可以移步这里。这篇文章接着前面的内容,介绍一下sequelize和sequelize-cli怎么使用。

什么是sequelize?

先看一下官方是如何解释Sequelize的?Sequelize 是一个基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, SQLite 和 Microsoft SQL Server. 它具有强大的事务支持, 关联关系, 预读和延迟加载,读取复制等功能。

首先解释一下ORM是什么?我们都知道DOM对吧。DOM叫做文档对象模型(Document Object Model),指的是像操作对象一样操作文档;而ORM叫做对象关系映射(Object Relational Mapping),换句话说就是像操作对象一样操作数据库。就是给前端提供操作数据库的一个便捷工具。

另外在安装sequelize之前需要先安装mysql2,因为sequelize本质上还是使用了sql语句对数据库进行增删改查。

什么是mysql2?

mysql2是一个极简快速的mysql库,与数据库建立连接,查询数据。我举个例子对比一下使用sequelize和mysql2查询同一条数据的差异。

  • mysql2版本:
router.post('/deleteItem', async (ctx,next) => {
    const id = Number(ctx.request.body.id) || 0;
    let sql = "DELETE FROM todos WHERE ??=?";
    const [res] = await connection.query(sql, ['id', id])
    console.log(res)
})
  • sequelize版本:
router.post('/deleteItem', async (ctx,next) => {
    const id = Number(ctx.request.body.id) || 0;
    let res = await Models.todos.findOne({
        where: {
            id: id
        }
    });
    console.log(res)
})

我们看到mysql2要写很多底层的sql,而且容易出错,不符合我们的书写习惯;而sequelize相对简单且符合书写习惯,所以sequelize更加友好。那sequelize-cli又是什么呢?

什么是sequelize-cli?

先看一下官方是如何解释这个东西的?sequelize-cli用于支持数据迁移和项目引导。通过迁移,可以将现有数据库迁移到另一个状态,反之亦然:这些迁移文件会被保存在迁移文件中,迁移文件描述了怎样到达新状态以及如何恢复更改以返回到迁移前的旧状态。

看起来有点拗口啊,我拿一个很常用的例子来类比一下。前端用vue比较多对吧,那么构建一个vue项目最常用的方式是什么呢?肯定是vue-cli脚手架了。那真相就显而易见了。sequelize-cli跟sequelize的关系就像vue-cli对于vue的关系。前者通过一种命令式的方式来对后者进行构建,换句话说就是一个构建sequelize环境的工具。在代码中用一个工具构建另外一个工具也是很常见的事。

知道了sequelize和sequelize-cli是什么之后,我们来学习sequelize和sequelize-cli怎么使用?既然sequelize-cli是构建sequelize环境的工具,那我们先从sequelize-cli开始讲起。

sequelize-cli怎么使用?

1、安装sequelize-cli sequelize mysql2

npm i sequelize-cli sequelize mysql2 --save

2、初始化sequelize环境

.\node_modules\.bin\sequelize init

这时候会出现config文件夹(配置文件夹),migrations文件夹(迁移文件夹),models文件夹(模型文件夹),seeders文件夹(种子文件夹)。

3、修改config.js文件

修改数据库名称和数据库密码。

4、创建并连接数据库

.\node_modules\.bin\sequelize db:create

如果此时连接和配置成功,会创建一个名为***的空数据库,则说明前面的配置和这次执行生效。

5、在迁移文件中创建表结构 比如下面我对comments.js文件的配置

up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('Comments', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      commentId: {
        allowNull: false,
        type: Sequelize.INTEGER
      },
      content: {
        allowNull: false,
        type: Sequelize.STRING
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    }, { // 数据库编码设置
        tableName: 'comments',
        charset: 'utf8mb4',
        collate: 'utf8mb4_bin'
    }).then(() => {
        queryInterface.addIndex('comments', {  // 把commentId设置为索引
            name: 'commentId',
            fields: ['commentId']
        });
    });
},

上面分别对id、commentId、content、createdAt、updatedAt的类型,是否为空等进行设置,并且设置commentId为索引。

按照上面的配置配置好后,执行.\node_modules\.bin\sequelize db:migrate即创建了各个表的表结构。

6、在种子文件中填充数据 我们可以通过各种方式,比如excel数据导出,拷贝等方式拿到种子数据。然后按照上面创建表的数据格式在seeders下创建种子文件,类似下面这种创建两条数据。然后执行语句.\node_modules\.bin\sequelize db:seed:all将数据填充到数据库中。

up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('Comments', [
        {
            commentId: 1,
            content: '困龙得水好运交,不由喜气上眉梢,一切谋望皆如意,向后时运渐渐高。',
            createdAt: new Date(),
            updatedAt: new Date()
        },
        {
            commentId: 1,
            content: '乾卦是根据万物变通的道理,以“元、亨、利、贞”为卦辞,示吉祥如意,教导人遵守天道的德行。',
            createdAt: new Date(),
            updatedAt: new Date()
        }
    ]
})

通过上面的6个步骤,就把数据库数据填充好了。当然你也可以写一个后台系统,将数据录入添加到数据库。因为时间关系我是直接生成种子文件导入到数据库中。现在数据有了如何使用sequelize语法拿到数据呢?

sequelize怎么使用?

1、前面说到sequelize是像操作对象一样操作数据库。通常我们说的这个对象是Models,就是把每一个表看成一个Model,然后去操作他。所以我们要向创建迁移文件一样创建Models。例子如下:

module.exports = (sequelize, Sequelize) => {
  const Comments = sequelize.define('Comments', {
    id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
    },
    commentId: {
        allowNull: false,
        type: Sequelize.INTEGER,
        references: {
            model: "Contents",
            key: 'contentId'
        }
    },
    content: {
        allowNull: false,
        type: Sequelize.STRING
    },
    createdAt: {
        allowNull: false,
        type: Sequelize.DATE
    },
    updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
    }
  }, {
    tableName: 'comments'
  });
  Comments.associate = function(models) {
    // associations can be defined here
    Comments.belongsTo(models.Contents, {
        foreignKey: 'commentId'
    });
  };
  return Comments;
};

这里有一个foreignKey值的概念,就是在进行多表查询时,我们需要有一个值跟这两个表之间进行关联,而这个值叫做外键,也就是这里foreignKey对应的值。上面这个映射关系说的是:Comments表中的多条数据对应Contents表。

按照上面的规则构建好Model之后,就可以开始使用sequelize语法按照条件查询数据库数据了。

2、以首页查询《易经64卦》作为例子:

const searchName = ctx.query.searchName || ''
// 查找包含某个字段的数据
let {count, rows} = await Models.Contents.findAndCountAll({
    where: {
        [Op.or]: [
            {
                name: {
                    [Op.like]: `%${searchName}%`
                }
            },{
                desc: {
                    [Op.like]: `%${searchName}%`
                }
            }
        ]
    },
})

先获取传入参数中的searchName,如果在字段name和desc中任意一个有包含searchName,那么这条数据就返回给前端。这里的count是查询出数据的总条数,rows是查询出数据的集合。

3、完成了koa部分的逻辑和上面的数据库查询逻辑后,执行node app.js启动web服务器,在浏览器输入localhost:3000/findContent?searchName=即可查询出数据。

总结

本篇文章我们引入了sequelize是像操作对象一样操作数据库工具的概念,然后解释了sequelize-cli是一个构建sequelize环境的工具。同时对比了一下mysql2和sequelize查询数据语法的区别,接着我们对照着项目的demo,讲解了一下如何使用sequelize-cli和sequelize把这个后端项目构建起来。

接下来会讲到这个demo部署上线的遇到的一些问题。

到了这里,可能大家对这个demo还有一些疑惑。因此我建了一个QQ群,群号码是:1103713567(全栈开发跳板群)。方便大家一起交流前端方面或者项目方面的问题。