面向前端工程师的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



如上内容均为本身总结,不免会有错误或者认识误差,若有问题,但愿你们留言指正,以避免误人,如有什么问题请留言,会尽力回答之。若是对你有帮助不要忘了分享给你的朋友或者点击右下方的“在看”哦!也能够关注做者,查看历史文章而且关注最新动态,助你早日成为一名全栈工程师!


相关文章
相关标签/搜索