1. 程式人生 > >node+express+grunt+mysql操作資料庫案例分析

node+express+grunt+mysql操作資料庫案例分析

簡單嘮兩句、

    在以前的node操作資料庫,都是選擇mongodb這型別的非關係型資料庫,進行資料儲存操作。而這次業務涉及到mysql,所以來簡單瞭解下node環境下,是如何操作mesql資料庫增刪改查的?

一、安裝

1. 開發依賴

yarn init
yarn add mysql
yarn add express
yarn global add add json-server # 本地服務工具
yarn global add add nodemon  / 或者 yarn add --dev grunt grunt-contrib-watch grunt-execute     # 自動化工具

2. 資料庫工具:Navicat for MySQL

  破解版下載地址:https://pan.baidu.com/s/1u8GGJ5AFFvAJKbXij4NyMA 提取碼: vhzc

二、開發測試思路

採用json-server啟動本地服務,預設啟動public目錄下index.html檔案,在index.html檔案中fetch請求express啟動的服務,根據請求的對應路由操作mysql資料庫

D:\me\npm\node-mysql>json-server db.json --port 3006

  \{^_^}/ hi!

  Loading db.json
  Done

  Resources
  http://localhost:3006/posts
  http://localhost:3006/comments
  http://localhost:3006/profile

  Home
  http://localhost:3006

  Type s + enter at any time to create a snapshot of the database

三、開發過程

1. 啟動mysql服務,新建資料庫,插入一些測試資料

(1)執行sql指令碼:

CREATE TABLE employees (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(50),
  location varchar(50),
  PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;

INSERT INTO employees (id, name, location) VALUES
(1, 'Jasmine', 'Australia'),
(2, 'Jay', 'India'),
(3, 'Jim', 'Germany'),
(4, 'Lesley', 'Scotland');

(2)或者手動插入

2. 新建/server.js檔案、public/index.html檔案

(1)server.js中開啟服務,配置允許跨域請求,連線mysql資料庫

// server.js
const mysql = require('mysql');
const app = require('express')();

//allow cross origin
app.all('*', function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  //Access-Control-Allow-Headers ,可根據瀏覽器的F12檢視,把對應的貼上在這裡就行
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  res.header('Access-Control-Allow-Methods', '*');
  res.header('Content-Type', 'application/json;charset=utf-8');
  next();
});

// First you need to create a connection to the db
const con = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'node'
});

con.connect((err) => {
  if(err){
    console.log('Error connecting to Db');
    return;
  }
  console.log('Connection established');
});

con.end((err) => { //注:在end之後就不能操作資料庫了! });

(2) 啟動node服務

C:\web\npm\node-mysql>node server.js
Connection established

(3) 根據需求或者個人喜好安裝nodemon/grunt自動編譯工具,如下是grunt的安裝

2-3-1. 安裝

C:\web\npm\node-mysql>cnpm install -g grunt grunt-contrib-watch grunt-execute

2-3-2. 檢視版本

C:\web\npm\node-mysql>grunt --version
grunt-cli v1.2.0
grunt v1.0.3

2-3-3. 新建一個Gruntfile.js檔案

module.exports = (grunt) => {
  grunt.initConfig({
    execute: {
      target: {
        src: ['./server.js']
      }
    },
    watch: {
      scripts: {
        files: ['./server.js'],
        tasks: ['execute'],
      },
    }
  });

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-execute');
};

2-3-4. 執行監聽

C:\web\npm\node-mysql>grunt watch
Running "watch" task
Waiting...
>> File "server.js" changed.
Running "execute:target" (execute) task
-> executing C:\web\npm\node-mysql\server.js
Connected !
-> completed C:\web\npm\node-mysql\server.js (254ms)

>> 1 file and 0 calls executed (270ms)

Done.
Completed in 0.835s at Tue Oct 23 2018 21:44:08 GMT+0800 (中國標準時間) - Waiting...

(4)index.html檔案中發出fetch請求服務,如下

fetch('http://localhost:3000/delete').then(res=>res.json()).then((res)=>{
    document.querySelector('#box').innerHTML += JSON.stringify(res);
});

2.查詢所有資料

// 查詢所有資訊
app.get('/getAll', function(req, res){
    connection.query('SELECT * FROM employees', (err,rows) => {
        res.send(rows);
    });
});

3. 插入資料資訊

app.get('/set', function(req, res){
    console.log('123');
    const employ = {name: '小虎的家鄉', location: '九寨溝'};
    connection.query('INSERT INTO employees SET ?',employ, (err,doc) => {
        res.send(doc);
        //{"fieldCount":0,"affectedRows":1,"insertId":5,"serverStatus":2,"warningCount":0,"message":"","protocol41":true,"changedRows":0}
    });
});

4. 更新資料

app.get('/update', function(req, res){
    const employ = ['大明王朝的芹菜',1];
    connection.query('update employees SET location = ? where ID = ? ',employ, (err,doc) => {
        res.send(doc);
        //{"fieldCount":0,"affectedRows":1,"insertId":0,"serverStatus":2,"warningCount":0,"message":"(Rows matched: 1 Changed: 1 Warnings: 0","protocol41":true,"changedRows":1}
    });
});

5. 刪除資訊

app.get('/delete', function(req, res){
    connection.query('DELETE FROM employees WHERE id = ?',4, (err,doc) => {
        res.send(doc);
        //{"fieldCount":0,"affectedRows":1,"insertId":0,"serverStatus":2,"warningCount":0,"message":"","protocol41":true,"changedRows":0}
    });
});

四、使用儲存過程查詢資料庫

1. 首先需要在navicat中執行如下查詢結構:

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_getall`()
BEGIN
  SELECT id, name, location FROM employees;
END

2. 然後在server.js中執行查詢服務

connection.query('CALL sp_getall()',function(err,rows){
    if(err) throw err;

    console.log('Data received form Db: \n');
    console.log(rows);
});

3. 列印如下:

Data received form Db:

[ [ RowDataPacket { id: 1, name: 'Jasmine', location: 'Australia' },
    RowDataPacket { id: 2, name: 'Jay', location: 'India' },
    RowDataPacket { id: 3, name: 'Jim', location: 'Germany' },
    RowDataPacket { id: 4, name: 'Lesley', location: 'Scotland' },
    RowDataPacket { id: 5, name: null, location: null } ],
  OkPacket {
    fieldCount: 0,
    affectedRows: 0,
    insertId: 0,
    serverStatus: 34,
    warningCount: 0,
    message: '',
    protocol41: true,
    changedRows: 0 } ]

五、使用儲存過程傳遞引數查詢

1. 執行sql語句

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_get_employee_detail`(
  in employee_id int
)
BEGIN
  SELECT name, location FROM employees where id = employee_id;
END

2. server.js中執行查詢

// 使用儲存過程查詢id為1的資料
connection.query('CALL sp_get_employee_detail(2)',function(err,rows){
    if(err) throw err;
    
    console.log('Data received form Db: \n');
    console.log(rows);
});

3. 列印如下:

Data received form Db:

[ [ RowDataPacket { name: 'Jasmine', location: 'Australia' } ],
  OkPacket {
    fieldCount: 0,
    affectedRows: 0,
    insertId: 0,
    serverStatus: 2,
    warningCount: 0,
    message: '',
    protocol41: true,
    changedRows: 0 } ]

五、使用儲存過程插入資料操作

1. 執行sql語句

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_insert_employee`(
  out employee_id int,
  in employee_name varchar(25),
  in employee_location varchar(25)
)
BEGIN
  insert into employees(name, location)
  values(employee_name, employee_location);
  set employee_id = LAST_INSERT_ID();
END

2. `query查詢` (前置條件:需要把connect的連線引數物件中增加欄位 multipleStatements: true )

connection.query( "SET @employee_id = 0; CALL sp_insert_employee(@employee_id, 'tiger', 'forest'); SELECT @employee_id",function(err,rows){
    if(err) throw err;

    console.log('Data received form Db: \n');
    console.log(rows);
});

3. 列印如下:

Data received form Db:

[ OkPacket {
    fieldCount: 0,
    affectedRows: 0,
    insertId: 0,
    serverStatus: 10,
    warningCount: 0,
    message: '',
    protocol41: true,
    changedRows: 0 },
  OkPacket {
    fieldCount: 0,
    affectedRows: 1,
    insertId: 0,
    serverStatus: 10,
    warningCount: 0,
    message: '',
    protocol41: true,
    changedRows: 0 },
  [ RowDataPacket { '@employee_id': 11 } ] ]

六、安全轉義引數

const userLandVariable = 4;
connection.query(
  `SELECT * FROM employees WHERE id = ${mysql.escape(userLandVariable)}`,
  function(err, rows){ 
    console.log(rows);
  }
);


// [ RowDataPacket { id: 4, name: 'Lesley', location: 'Scotland' } ]

七、結論

無論什麼時候,不管遇到什麼情況,我絕不允許自己有一點點灰心喪氣。—— 愛迪生