[ 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方法中調用,並且額外將資料包裝才能正確回傳
並且還可以將兩者邏輯解偶
三、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
**
四、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
})
這時如果查詢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結束