iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
0
自我挑戰組

後端工程師自我練習,使用Node.js來做後端server系列 第 8

[Day-8] Node.js [使用Express結合Knex進行資料庫操作& Transaction]

  • 分享至 

  • xImage
  •  

[ Day 8]

說明:
今天來結合day7和day6的套件,完成一個可以透過http request進行資料庫CRUD的restful API

一、資料庫設定檔
knexCofig.js

const knex = require('knex')({
  client: 'mysql',
  connection: {
    host : 'localhost',
    user : 'root',
    password : '123456',
    database : 'demo'
  }
});

module.exports = knex

首先將資料庫連線設定的knex內容額外包裝成一個knexConfig模組,以利重複使用
在expressUser.js中引入此模組

const knex = require('./knexConfig')

二、http get user查詢使用者資料

userApi.get('/', (req, res) => {

  var request = JSON.parse(req.body)
  var userName = request.name
  getUser(userName)
    .then(rtn => {
      var results =  new Array()
      for(var result in rtn) {
        results.push({
          'userName': rtn[result].user_name,
          'userId': rtn[result].user_id
        })
      }
      res.send('user info is ' + JSON.stringify(results))
    })
    .catch(err => {
      res.status(500).send(err.toString())
    })
})
async function getUser(conditions) {
  var results
  await knex('user')
  .select('user.user_id', 'user.user_name', 'user_ii.gender')
  .leftJoin('user_ii', 'user.user_id', 'user_ii.user_id')
  .where('user_name', 'like', conditions)
  .then((resultArray) => {
    results = resultArray
  }).catch((err) => {
    console.error(err)
    throw err
  })

  return results
}

這裡結合了knex與express
需注意的是,knex本身是非同步方法,如果不使用async,await等待完成
而直接在getUser方法後回傳res.send,會產生資料還未取回就回傳空資料的狀況

**關於javascript非同步async,await,Promise的相關資料:
**參考 : https://wcc723.github.io/javascript/2017/12/29/javascript-proimse/

將knex取資料的方法額外包成一個aysnc方法,在get方法中調用,並且額外將資料包裝才能正確回傳
並且還可以將兩者邏輯解偶
https://ithelp.ithome.com.tw/upload/images/20200921/20110911hl8uun9cHy.png

三、post方法 新增使用者

userApi.post('/', (req, res) => {
  var user = JSON.parse(req.body)
  insertUser(user)
    .then(rtn => {
      res.send('insert user data, new user id is ' + rtn)
    })
    .catch(err => {
      res.status(500).send(err.toString())
    })
})
async function insertUser(userInfo) {
  var successId
  await knex('user')
  .insert({ 
    'user.user_name' : userInfo.name
  })
  .returning('user_id')
  .then((result) => {
    console.log(result)
    successId = result
  }).catch((err) => {
    console.error(err)
    throw err
  })

  await knex('user_ii')
  .insert({ 
    'user_ii.user_id' : successId,
    'user_ii.gender' : userInfo.gender
  })
  .then((result) => {
    console.log(result)
  }).catch((err) => {
    console.error(err)
    throw err
  })

  return successId
}

這裡將傳入的request body參數parse後當成方法參數傳入非同步insertUser方法裡
同時新增user以及user_ii兩個table
**需注意的是,這裡並沒有使用上transaction,如果在新增user_ii時發生錯誤,理應將user資料也rollback
**
https://ithelp.ithome.com.tw/upload/images/20200921/20110911ItUzKqIuiO.png

四、no transaction
這裡示範沒有transaction的情況下會造成髒資料的情況
將int欄位放入字串

  await knex('user_ii')
  .insert({ 
    'user_ii.user_id' : successId,
    'user_ii.gender' : 'userInfo.gender'
  })
  .then((result) => {
    console.log(result)
  }).catch((err) => {
    console.error(err)
    throw err
  })

https://ithelp.ithome.com.tw/upload/images/20200921/201109117qijINQEpF.png
這時如果查詢user_ii table會發現user_ii資料因為發生錯誤沒有寫入資料
但是user table卻有,這不是我們希望的狀況,要嘛就是全寫入,要嘛就是全沒寫入

五、transaction

async function insertUser(userInfo) {
  var successId

  await knex.transaction(async (trx) => {
    await knex('user')
      .transacting(trx)
      .insert({
        'user.user_name': userInfo.name
      })
      .returning('user_id')
      .then((result) => {
        successId = result
      }).catch((err) => {
        console.error(err)
        throw err
      })


    await knex('user_ii')
      .transacting(trx)
      .insert({
        'user_ii.user_id': successId,
        'user_ii.gender': userInfo.gender
      })
      .then((result) => {
        console.log(result)
      }).catch((err) => {
        console.error(err)
        throw err
      })
  })

  return successId
}

這裡使用knex.transaction將insert兩個table的方法包含在裡面
並且單獨的insert語句需加上transacting(trx)
再次測試user_ii會發生錯誤的情況,這時候user會發生rollback沒有寫入。

至於修改和刪除方法類似於上面的情況,就不再放上了。

Day8結束


上一篇
[Day-7] Node.js [使用Express套件建立REST API]
下一篇
[Day-9] Node.js [使用Passport.js進行會員驗證 - 1 (passport-local)]
系列文
後端工程師自我練習,使用Node.js來做後端server30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言