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

相關文章
相關標籤/搜索