面向前端工程師的Nodejs入門手冊(四)

數據庫,網站系統最重要的部分之一,它比如一我的的大腦,能夠記下開發者們想讓它記下任何的事情,並且它比人腦更可靠更精準。javascript

實質上,任何數據庫均是文件系統,可是它與咱們在桌面上右鍵新增的文件相比而言,數據庫則是有規則的文件系統,不像咱們普通新增一個文件即可以隨意寫東西進去,數據庫文件會有專門的存貯規則和特定操做數據內容的方式。前端

最多見的SQL語句其實就是一種操做規範,它約束了增刪改查必需要經過規定的方式,像select,update, delete等特定語句,最終將生成的是規範化數據內容。java

接下來看看Nodejs能不能操做這個網站的「記憶系統」呢?若是能夠操做又是如何操做的呢?一塊兒進入Nodejs與數據庫的內容學習吧。node

文件數據庫

數據庫的本質是存儲數據,咱們平時用的文件自己也是存儲數據,那麼咱們只要制定一個規範,那普通文件也能夠是一個數據庫,並且普通文件不依賴環境,你沒必要安裝引擎或者工具之類的才能操做,它是操做系統自帶的能力,因此某些場景更符合使用。mysql

舉個栗子,好比你的應用是客戶端應用,像一些客戶端配置或者狀態數據並不想經過上傳到雲端的服務器上,而就是想存在客戶端本地,起到相似於瀏覽器上的localStorge的做用,這時候你即可以新增一個文件做爲數據庫來使用。git

在Nodejs中,lowdb模塊[1]即是被用於文件數據庫的封裝庫,它的規範就是咱們熟知的json規範,使用它無需安裝其餘軟件,僅須要咱們有nodejs環境便可。github

安裝sql

npm i --save lowdb複製代碼

示例:mongodb

// app.js
const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');

// 同步文件類型
const adapter = new FileSync('db.json');
const db = low(adapter);

// 初始化數據庫字段
db.defaults({ userInfo: {}, time: '' }).write();

db.set('userInfo.name', '全棧者').write();
db.set('userInfo.title', '歡迎關注').write();
db.set('time', new Date()).write();

const userInfo = db.get('userInfo').value();
const time = db.get('time').value();

console.log(`userInfo: %o`, userInfo);
console.log(`time: %s`, time);
// userInfo: { name: '全棧者', title: '歡迎關注' }
// time: Tue Aug 27 2019 16:06:13 GMT+0800 (CST)複製代碼

再看看db.json文件裏的內容docker

{
  "userInfo": {
    "name": "全棧者",
    "title": "歡迎關注"
  },
  "time": "2019-08-27T08:06:13.991Z"
}複製代碼

非關係型數據庫

非關係型數據庫也是一種很是經常使用的數據庫,通常的咱們所用到的MongoDB,CouchDB都屬於此類,非關係型的數據庫和上面的文件數據庫其實很相似,它也是基於鍵值對做爲存儲規範。

可是相比於上面來講,它的自身作了不少限制與規範。它被普遍使用在非關係數據的存儲上,性能相比較與關係型數據庫也是很是不錯,通常大型的應用都會將非關係數據庫與關係型數據庫的共同協做使用。

這裏就以Mongodb來看看Nodejs是如何操做非關係型數據庫的。

首先安裝Mongodb,這裏仍是推薦使用docker去安裝mogodb。

docker search mongo
docker pull mongo
# 拉下來以後啓動的時候要把本機的數據文件位置與docker容器進行關聯
# 在docker中使用 -v 進行掛載
# docker啓動鏡像, -p 暴露27017端口, 
# 下面的文件路徑要替換成你的機器上的一個要存放db文件的文件路徑,好比我在 ~/Desktop/Practice-book/nodejs/db/mongodb/db 
# 下存放個人db文件,那個人文件路徑就是 ~/Desktop/Practice-book/nodejs/db/mongodb/db
docker run -p 27017:27017 -v ~/Desktop/Practice-book/nodejs/db/mongodb/db:/data/db -d mongo
# 啓動完成查看一下
docker ps複製代碼

~/Desktop/Practice-book/nodejs/db/mongodb/db 文件夾下會多出一些以下文件。

接下來進行鏈接與操做mongodb數據庫,這裏選用使用量較高的mongoose模塊。

安裝mongoose

cnpm i --save mongoose複製代碼

示例:

const mongoose = require('mongoose');

mongoose.connect('mongodb://127.0.0.1:27017/db', { useNewUrlParser: true });

mongoose.connection.on('error',() => {
  console.log('鏈接錯誤:')
});

// 定義存儲數據的sechema
const Sechema = new mongoose.Schema({
  name: String,
  title: String,
  time: Date,
});

// 定義數據模型,模型便可直接操做數據,如建立查詢更新刪除等。
const Model = mongoose.model('person',Sechema);

Model.create({
  name: '全棧者',
  title: '歡迎關注',
  time: new Date(),
})

Model.find({}, function(err, data) {
  if(err) {
    console.error(err);
  } else {
    console.log(data);
  }
});

Model.findById('5d64f210e38a73dce44956bf', function(err, data) {
  if(err) {
    console.error(err);
  } else {
    console.log('id: 5d64f210e38a73dce44956bf');
    console.log(data);
  }
});複製代碼

上面這段代碼,先鏈接了docker提供的mongodb服務,而後定義了咱們要存進Mongodb的數據Sechema,Sechema的做用就是限定存入mongodb的字段數據類型,如Number,String等基本類型。

接着定義了一個模型Model,Model便可理解爲暴露出的一張表的操做對象,如新增查找更新刪除等都在Model上,例子中的Model就是操做person表的操做對象,它裏面有find,create等一些方法。重複執行了幾回node app後,看看上面代碼的執行結果。

關係型數據庫

關係數據庫是目前使用體量最大,最普遍的數據庫了,它的優勢很是明顯,首先從它二維表的結構設計是很是貼近邏輯世界概念,關係模型相對網狀、層次等,對人來講很容易理解,同時它豐富的完整性也大大減低了數據冗餘和數據不一致的機率,保證數據的準確一致性。

還有最大的亮點就是支持SQL語句了,有了SQL語句不少複雜的查詢均可以被實現,如多個表之間的操做即可以經過一個SQL語句實現,很是便捷。固然同時也由於多了SQL層解析,它相比於非關係型數據庫讀寫性能相對較低。

在這裏的所演示的關係型數據庫採用最經常使用的mysql,來看看Nodejs是如何操做關係型數據庫mysql的。

1. 首先安裝mysql,這裏仍是使用docker去安裝mysql,和上面mongodb的安裝同樣的步驟。

docker search mysql
docker pull mysql
# 拉下來以後啓動的時候要把本機的數據文件位置與docker容器進行關聯
# docker啓動鏡像, -p 暴露3306端口
docker run -p 3306:3306  -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6
# 啓動完成查看一下
docker ps複製代碼

2. 安裝可視化操做工具,筆者推薦datagrip工具操做數據庫,可是要收費(囧),我這邊使用免費的sequelPro。


3. 進行建庫建表操做,使用建表語句[2] 建表完成。

4. 接下來使用Nodejs來操做mysql,這裏使用mysql模塊來演示。

安裝mysql模塊

cnpm i --save mysql複製代碼

示例:

const mysql = require('mysql');

const connection = mysql.createConnection({
  host: '127.0.0.1',
  port: 3306,
  user: 'root',
  password : '123456',
  database : 'Test_DB'
});
 
connection.connect(function(err) {
  if (err) {
    console.error('error connecting: ' + err.stack);
    return;
  }
  console.log('connected as id ' + connection.threadId);
});

const insert = `INSERT INTO Tab_User_Info (name, title, description) VALUES ('全棧者', '歡迎關注', '微信公衆號:全棧者')`

// 插入一條數據到Tab_User_Info表
connection.query(insert, function (error, results) {
  if (error) console.log(error);
  // affectedRows 影響行數,爲1時則證實插入成功了
  if (results.affectedRows === 1) {
    console.log('插入成功');
    selectTable();
  }
});

// 查詢Tab_User_Info表全部數據
function selectTable() {
  const select = `Select * from Tab_User_Info`;
  connection.query(select, function (error, results) {
    if (error) console.log(error);
    console.log(results)
  });
}複製代碼

上面Nodejs操做Myql的例子完成了,首先咱們使用mysql提供的createConnection接口鏈接docker啓動的mysql服務,而後編寫插入SQL語句,使用鏈接數據庫後query接口進行執行編寫好的SQL語句,執行完成以後進行一次查詢。

5. 結果以下

實戰

1. 需求

給前端提供一個接口,該接口內容能夠由mogodb提供,也能夠由mysql提供,可是由那個數據庫提供並不是隨機決定的,而是須要內部人員進行開關控制。

2. 實現思路

a. 首先能夠根據需求要提供兩個接口,一個是內部人員使用的開關接口,另外一個是提供給前端使用的數據接口。

b. 開關接口只須要存儲當前數據接口處於那種模式,是一種狀態值,在某一時刻只處於一種狀態 ,因此這裏適合使用FileDB就記錄狀態。

c. 數據接口的提供者由FileDB內的狀態值來決定,因此在用戶數據接口請求時先獲取FileDB內的狀態判斷。

3. 代碼示例:

// http.js
const http = require('http');
const url = require('url');
const qs = require('querystring');

const fileDB = require('./fileDB');
const mongodb = require('./mongodb');
const mysql = require('./mysql');

const genResponse = message => JSON.stringify({
  success: true,
  data: message
});

http.createServer((req, res) => {
  res.setHeader('Content-Type', 'application/json;charset=utf-8');
  const reqUrl = url.parse(req.url);
  if (reqUrl.pathname === '/api/set/db') {
    // 開關接口
    const { db } = qs.parse(reqUrl.query);
    if (['mongo', 'mysql'].includes(db)) {
      fileDB.set('curDb', 'mongo').write();
    } else {
      return res.end(genResponse('參數有誤'));
    }
    fileDB.set('curDb', db).write();
    fileDB.set('updateTime', new Date()).write();
    const result = genResponse(`修改數據庫模式爲:${db}`);
    res.end(result);
  } else if (reqUrl.pathname === '/api/get/data') {
    // 數據接口
    const db = fileDB.get('curDb').write(); //獲取當前狀態
    if (db === 'mongo') {
      // 獲取mogondb數據
      mongodb.find({}, function(err, data) {
        if(err) {
          console.error(err);
          return res.end(genResponse(err));
        } else {
          const result = genResponse(data);
          res.end(result);
        }
      });
    } else {
      // 獲取mysql數據
      const select = `Select * from Tab_User_Info`
      mysql.query(select, function (error, results) {
        if (error) {
          console.log(error)
          res.end(genResponse(error));
        } else {
          res.end(genResponse(results));
        }
      });
    }
  } else {
    res.writeHeader(404);
    res.end('NotFund');
  }
}).listen(8000, ()=> {
  console.log('listen on 8000!');
})複製代碼

    上面的示例中提供了一個開關接口 /api/set/db , 該接口由內部人員觸發,來設置數據接口的提供者,另外一個是數據接口/api/get/data ,該接口用來給前端提供數據,該接口被觸發時,先要獲取開關接口所設置的狀態值,而後執行查操做,以後返回數據。

 4. 結果展現 

 a. 開關接口設置數據庫爲mysql


b. 開關接口設置數據庫爲mongo

References

[1] lowdb模塊:

https://www.npmjs.com/package/lowdb

[2] 建表語句:
https://github.com/FantasyGao/Practice-book/blob/master/nodejs/db/mysql/test.sql


本文所用的的代碼都可在下面找到,有興趣的clone下來動手練習。

文章用到的代碼都可在此獲取:

https://github.com/FantasyGao/Practice-book/tree/master/nodejs/db



如上內容均爲本身總結,不免會有錯誤或者認識誤差,若有問題,但願你們留言指正,以避免誤人,如有什麼問題請留言,會盡力回答之。若是對你有幫助不要忘了分享給你的朋友或者點擊右下方的「在看」哦!也能夠關注做者,查看歷史文章而且關注最新動態,助你早日成爲一名全棧工程師!


相關文章
相關標籤/搜索