eggjs搭建后端博客系统(一),记录解决sql事务问题

废话部分

该项目git地址:https://github.com/ht-sauce/dream-admin前端

惯例:我的的废话部分vue

我的是前端开发,可是公司有时候比较闲。因此就想着本身写点东西,老摸鱼,太没意思了,还有一个就是装逼和加薪。java

后端这块我比较早之前用过express,本身开发过简单的后端管理系统。node

最近一年多正式作了开发,一开始我先搭建了个人前端博客页面(如今想起来是单页面项目,并不完美,最好是用服务端渲染来开发的)。后面博客系统确定须要有后端因此,继续用nodejs是没错的。我不打算用java,或者go语言之类的。对于我这样的菜鸟,贪多嚼不烂。并且java是我见过最笨重的语言之一。java的开发很繁琐,历史包袱重。新手教程很是不友好。自学难度入门很难。进门以后又容易被不完美的教程带偏(缺这个少那个)。mysql

java主要缘由是由于早期没有一个包管理系统(目前的go语言等没有这个问题),致使了java在包管理上的混乱。致使新手不友好。react

总体项目我是模拟大项目的。git

项目目前分为四大块。程序员

博客系统(我的生活展现平台,记录平台)github

会员系统(负责登陆和权限的统一管理,将登陆和人员部分单独分离)算法

接口管理系统(就是一个接口记录平台)

后端管理平台

想法上很是美好,可是我目前为止后端才刚开始搞。前端基本页面差很少,可是没有后端的数据配合,写了总感受缺乏什么。虽然也能写啦,可是和后端不一样,前端我写了一年多。感受没有什么大挑战了。只是写的慢和快的问题,加上公司也不必定会有一些我设想中的东西。因此本身写后端,本身玩。(可是本身仍是很懒,三个月才这么点)。

后端项目选型

1、框架选型

express确定不会用了,因此后端我也就剩下koa框架了。(这块主要是参考招聘网站中经常使用的框架,并且结合市场去学习选型)

koa框架我官网看过,比express好不少。可是koa有种react的感受,什么都须要本身弄。express也是同样的。

后面在逛论坛(cnode社区)下,发现cnode基本放弃express使用koa,jest和eggjs框架。其中eggjs是最多的。而后也去官网看了看。

eggjs最大的优势是他是阿里的,它用于双十一了。还有eggjs帮初学者和新手继承了很是多的功能。就像vue脚手架,初始就给你把架子搭建好了。你再也不须要本身去作那些繁琐的事情,并且是业界大神帮你搭建的。

举例:

基础安全机制

日志系统

多进程负载

等……

其中多进程负载是我很看重的,由于这个新手老手都不必定能搞定。这是nodejs能利用多核cpu的关键。

2、基础学习

推荐个人这个文章看看,很好的入门视频教程。下载不了的请留言。我找时间本身上传百度云看看。

https://juejin.im/post/5d6c872ae51d4561f64a0862

3、插件选型

由于egg对后端的基础环境作了很是良好的集成。因此咱们再也不须要作繁琐的初始工做注重开发就好了。可是仍是须要作基础的选型。主要是数据库链接上。

我说句很差听的,为何后端程序员经常会被嘲讽为增删改查工程师。甚至是一些后端人员认为本身很牛逼(实际上只是会增删改查)。这不懂后端的你们不知道,懂了的会发现。后端入门以后基本上的事情就是链接数据库查询结果,插入数据,返回数据。就是这么简单会sql,甚至是部分代码只须要复制黏贴就好了。格式整齐划一。因此后端我认为主要牛逼在多年经验和算法。一个初级的后端程序员比前端简单,可是后端比前端工资高。为何呢?由于前端没了后端走不了业务,后端能够离开前端(简单的页面)。其实很是不公平,若是二者分开,初级前端比初级后端强。特别是当下的前端环境。

说了这么多,其实全部的一切在初级后端下,咱们只须要搞定框架和数据库链接插件就ok了。恩,还有写接口。

mongdb:egg-mongoose(也就是mongoose)

在数据库上面nodejs目前分为两大块,一个是mongdb和mysql。一个是nosql一个是关系型数据库。二者我都用过,可是在nosql上我表示本身不够熟练,还有就是在数据库建模方面总以为有问题因此我放弃了。

那么只有mysql了。

mysql的选择很少,主要是mysql官方插件和orm插件(sequelize

比较方面:

mysql:

egg-mysql:

就是传统的sql语句,主要缺点是开发人员容易发生数据库语句拼接,发生sql注入。

egg-sequelize

不少人说性能问题,这个能够忽略不计。最大问题在于非关系型语句操做。所有是封装好的对象编写方式。关键在于学习了sql语句以后还须要学习这个。可是不得不说,orm框架简化了一些sql的编写问题。

接口整合方面:

graphql:

很是不喜欢,文档少,并且繁琐。总感受目前而已意义不大。虽然很诱人的感受。

4、链接数据库。

基础的数据库安装我就不教了。我用mysql8.X

数据库链接很简单,egg封装上都作好了。

先执行

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

而后配置数据库链接

\dream-admin\config\plugin.js

配置插件

'use strict';

/** @type Egg.EggPlugin */
module.exports = {
  static: {
    enable: true,
  },
  sequelize: {
    enable: true,
    package: 'egg-sequelize',
  },
};复制代码

配置数据库链接(mysql时间格式转化也写好了。看配置)

\dream-admin\config\plugin.js\config.default.js

/* eslint valid-jsdoc: "off" */

'use strict';

module.exports = appInfo => {
  const config = exports = {
    static: { prefix: '/dreamdht/' },
    keys: appInfo.name + '_1568770372144_7988',
    security: {
      csrf: {
        ignore: () => true,
      },
    },
  };
  config.sequelize = {
    dialect: 'mysql', // support: mysql, mariadb, postgres, mssql
    database: 'dream',
    host: 'localhost',
    port: 9906,
    username: 'root',
    password: '1111',
    timezone: '+08:00',
    // 时间格式转化
    dialectOptions: {
      dateStrings: true,
      typeCast: true,
    },
  };
  return config;
};复制代码

5、写模型

orm框架和传统数据库插件相比,多了模型的编写这一步。至关于数据库建表,建模。

egg框架全部业务模型都放在app\model文件下面

个人是这样的


拿出一个模型例子:userInfo

这里我不作多余延伸。由于这篇文章主要是记录数据库操做的问题。整篇文章涉及不少知识点。每一项都须要很大的精力去阅读文档。特别是没有后端基础那更加是看不了的。

'use strict';
module.exports = app => {
  const { STRING, INTEGER, DATE, ENUM } = app.Sequelize;

  const UserInfo = app.model.define('consumer-userInfos', {
    userid: {
      type: INTEGER,
      primaryKey: true,
      comment: 'user帐号表id',
    },
    nickname: {
      type: STRING(30),
      allowNull: false,
      defaultValue: '',
      comment: '昵称',
    },
    portrait: {
      type: STRING(200),
      comment: '用户头像',
    },
    sex: {
      type: ENUM('男', '女'),
      comment: '性别',
    },
    phone: {
      type: STRING(15),
      comment: '联系电话',
      unique: true,
    },
    birthday: {
      type: DATE,
      comment: '生日',
    },
    provinceAndCity: {
      type: STRING(30),
      comment: '省市区域码',
    },
    address: {
      type: STRING(100),
      comment: '详细住址',
    },
    qq: {
      type: STRING(100),
      comment: 'qq或微信信息',
    },
    email: {
      type: STRING(50),
      comment: '邮箱地址',
      unique: true,
    },
  }, { comment: '用户信息表,每一个用户惟一' });

  return UserInfo;
};复制代码


6、服务编写(service层,业务逻辑编写所有在这里)

这里同样说文章主要目的。

下面的语句包含两部分,一个是sql事务,还有一个是关于现代nodejs框架配合async\await如何处理错误。

sql事务,主要看注释。我以前犯错主要在这里

await ctx.model.Consumer.UserInfo.create(data, { transaction });复制代码

错误的方式:

await ctx.model.Consumer.UserInfo.create(data, transaction );复制代码

错误处理

eggjs在错误处理上和传统的后端很像了,主要是靠try\catch捕获错误。

而后我这里的逻辑调用在于我是控制层访问——服务层——访问——数据库

那么服务层其实就能捕获数据库错误了。可是在控制层我同样是用try\catch来捕获错误。那么你应该在我下面代码同样。用

// 返回错误信息
return Promise.reject(e);
// 或throw e;复制代码

来返回错误结果,保证控制层也正常的报错

直接上代码:

'use strict';
const Service = require('egg').Service;

class UserService extends Service {
  async find() {
    const { ctx, app } = this;
    const sequelize = app.Sequelize;
    const query = [[ sequelize.fn('COUNT', sequelize.col('id')), 'num' ]];
    // console.log(result[0].dataValues.num);
    return await ctx.model.Consumer.User.findAll({
      attributes: query,
    });
  }
  // 建立用户帐号和用户信息
  async create(data) {
    // 获取当前条目数加1做为主键id
    const { ctx, app } = this;

    const sequelize = app.Sequelize;
    const query = [[ sequelize.fn('COUNT', sequelize.col('id')), 'num' ]];
    const count = await ctx.model.Consumer.User.findAll({
      attributes: query,
    });

    const id = count[0].dataValues.num + 1;
    data.id = id;
    data.userid = id;
    let transaction;
    try {
      // 启用事务
      transaction = await ctx.model.transaction();
      // 建立帐号
      await ctx.model.Consumer.UserInfo.create(data, { transaction });
      await ctx.model.Consumer.User.create(data, { transaction });
      // 提交事务
      await transaction.commit();
      return true;
    } catch (e) {
      // 错误事务回滚
      await transaction.rollback();
      // 返回错误信息
      return Promise.reject(e);
    }
  }
}

module.exports = UserService;复制代码


七:总结

文章主要三点:

Sequelize下面事务的使用。格式很标准。

// 启用事务 

 transaction = await ctx.model.transaction();

// 建立帐号 

sql业务操做 

//提交事务

transaction.commit();

当发生错误的时候进行回滚

await transaction.rollback();

而后是事务使用的时候注意事项。代码格式别错了。

还有就是mysql时区致使查询出来的结果时间格式不对

8、致谢

感谢eggjs团队开源框架

参考文章:

sequelize中文文档:https://demopark.github.io/sequelize-docs-Zh-CN/

参考博客:https://blog.csdn.net/awhlmcyn/article/details/79816494

参考博客:https://blog.csdn.net/clearlxj/article/details/94597734

相关文章
相关标签/搜索