node.js + mysql 實現資料新增的功能。萬事基於服務!
增刪改查之新增資料。
優點:只需要設定一個json檔案,就可以實現基本的新增功能,可以視為是零程式碼。
新增資料的服務實現的功能:
1、 新增一條記錄、多條記錄(批量新增)、主從表記錄
2、 記錄訪問日誌
3、 記錄資料變化記錄
4、 執行步驟跟蹤和計時
5、 異常日誌
6、 許可權判斷
步驟:
1、 資料庫設計、建表這類的直接略過,假設有了一張表,我們要往這個表裡面新增資料
2、 根據要新增的欄位,設定一個json檔案,對服務進行描述,並且給這個服務設定一個變化,作為區分。
3、 客戶端提交資料和服務變化。
4、 伺服器端,獲取資料和服務變化,呼叫對應的程式進行處理。
5、 處理完畢後處理返回給客戶的資訊
6、 如果有特殊業務需求,可以用外掛的方式來實現。
7、 完成
第一步,不管用什麼方式做專案,都是要做的。
第二步需要弄一個json檔案,這個可以自動生成,不用手寫
第三步相當於做一個路由,路由規則制定好了就不用再寫程式碼了。
第四步由框架完成,不需要寫程式碼
第五步判斷一下是否成功,按照規則給瀏覽器返回資料,也不用一遍一遍寫。
第六步不是必須的,大部分的增刪改查都是不需要外掛的。
所以,基本上做一個json檔案,就可以搞定一個服務。需要寫的程式碼無限接近零程式碼。而json檔案又可以自動生成。
下面是json檔案的例子:(這個可以自動生成)
{ "operationMode":"add", "pluginBefore":"", "pluginAfter":"", "tableInfo":{ "tableName": "node_user", "primaryKey":"id", "sql": "INSERT INTO node_user(id,name,age) VALUES(0,?,?)" , "sqlSelect": "SELECT * FROM node_user WHERE id = ?" , "column":["name","age"] } }
然後再說一下程式碼型別,可以分為兩類——框架類和專案類。
像.net框架、ado.net、express這類,內部的實現程式碼都是屬於框架級的,內部有再多的程式碼,也不應該算到專案裡面。
而呼叫類庫、使用框架實現專案的程式碼,才是專案級的程式碼,才算作程式碼量。
這個要先說清楚,然後再發後面的程式碼。
http的使用,屬於專案級的,http的內部實現,就是框架級的。
同理,新增服務的呼叫部分屬於專案級的,服務內部的實現程式碼屬於框架級的。
先不上http了,寫一個簡單的測試用程式碼,優點是不用開啟瀏覽器就可以進行測試。要不然每次都要開啟瀏覽器,太麻煩了。
這個不是正式的程式碼,僅僅是初期測試用的。這個是專案級別的程式碼。
/** * Created by jyk00 on 2019/3/31. * curd的服務 */ //測試新增服務 //精確計時 var time = require('../preciseTime').time; //建立新增服務物件 var service = require('./serviceAdd'); var trace={ title:'收到一個請求:100', msg:'', startTime:time(), endTime:0, useTime:0, items:[] }; service.start(100,trace,function (err,info) { msg.endTime = time(); msg.useTime = time() - msg.startTime; console.log('完成服務:'+JSON.stringify(trace)); });
新增服務的程式碼(業務層) 框架級程式碼
/** * Created by jyk00 on 2019/3/31. * 新增資料的服務 */ exports.start = function(code,trace,callback) { //精確計時 var time = require('../preciseTime').time; var traceAdd = { title:'開始新增資料的服務', msg:'', startTime:time(), endTime:0, useTime:0, items:[] }; trace.items.push(traceAdd); /** 根據配置資訊實現新增資料的功能 * 獲取服務資訊 * 接收資料 * 驗證資料 * 呼叫外掛 * 持久化 * 獲取持久化後資料 * 寫資料變化日誌 * 返回結果 */ //獲取服務資訊 //console.log('服務ID:' + code); var meta = require('./service_'+ code +'.json'); console.log('獲取服務資訊:' + meta); //獲取實體類,先模擬一下 var data = require('./node_user.json'); var info={ trace:traceAdd, requestId:0, serviceId:code, data:data, table:meta.tableInfo }; //驗證資料,暫時略 //呼叫持久化前的外掛 var plugName = meta.pluginBefore; if (plugName.length === 0){ //沒有外掛,不呼叫 console.log('沒有外掛,不呼叫'); //持久化及後續 saveAndLast(data); } else { //有外掛 console.log('有外掛,呼叫'); var plug = require('../plugin/' + plugName); plug.begin(data,function(data){ //持久化及後續 saveAndLast(data); }); } //持久化以及之後的事情 function saveAndLast(data) { //持久化之新增資料 var db = require('./dataBaseAdd'); //持久化 db.query(info,function(err, result){ console.log('saveData的回撥:' ); console.log('result:',result); //呼叫持久化之後的外掛 plugName = meta.pluginAfter; if (plugName.length === 0){ //沒有外掛,不呼叫 } else{ //有外掛 plug = require('../plugin/' + plugName); plug.begin(err, result,data,function() { }); } }); } };
持久化的程式碼(資料層) 框架級程式碼
/** * Created by jyk00 on 2019/4/1. * 資料服務之新增操作 */ //持久化內部的跟蹤 var traceStartAddData = {}; //捕捉異常 process.on('uncaughtException', function (err) { console.log('uncaughtException的trace:' +JSON.stringify(traceStartAddData)); console.log("捕捉到異常啦"); console.log(err); }); exports.query = function(info,callback) { //精確計時 var time = require('../preciseTime').time; //持久化之新增資料 traceStartAddData = { title:'持久化之新增資料', msg:'', startTime:time(), endTime:0, useTime:0, items:[] }; info.trace.items.push(traceStartAddData); /** 根據配置資訊實現新增資料的功能 * 獲取表資訊 * 接收傳入的資料,驗證任務由上層搞定 * 持久化 * 獲取持久化後資料 * 寫資料變化日誌 * 返回結果 */ //==================獲取表資訊和資料================================= var traceGetInfo = { title:'獲取表資訊和資料、定義dataChange', msg:'', startTime:time(), endTime:0, useTime:0, items:[] }; traceStartAddData.items.push(traceGetInfo); //獲取表資訊 var tableInfo = info.table; //獲取實體類 var data = info.data; //記錄資料變化情況 var dataChange = { requestId:info.requestId, serviceId:info.serviceId, tableID:info.table.tableId, dataID:0, oldDataJson:'', newDataJson:'', submitDataJson:JSON.stringify(info.data), dbResult:'', trace:JSON.stringify(info.trace), addUserid:1 }; traceGetInfo.endTime = time(); traceGetInfo.useTime = time() - traceGetInfo.startTime; //==================建立MySql物件================================= var traceCreateMySql = { title:'建立MySql物件、cnString、connection', msg:'', startTime:time(), endTime:0, useTime:0, items:[] }; traceStartAddData.items.push(traceCreateMySql); //建立mysql物件 var mysql = require('mysql'); var cnString = require('../sqlConnection.json'); var connection = mysql.createConnection(cnString); traceCreateMySql.endTime = time(); traceCreateMySql.useTime = time() - traceCreateMySql.startTime; //==================傳送持久化請求================================= var traceAddNewData = { title:'準備傳送持久化請求,新增一條資料', msg:'', startTime:time(), endTime:0, useTime:0, items:[] }; traceStartAddData.items.push(traceAddNewData); var sql = tableInfo.sql; //資料轉換成陣列 var valuesParams = createParams(tableInfo,data); myQuery(sql,valuesParams,traceAddNewData,function (err, result) { //資料新增完成後的回撥 //console.log('持久化的回撥的trace:' +JSON.stringify(traceStartAddData)); if(err){ console.log('[INSERT ERROR ] - ',err.message); traceAddNewData.msg += '_err:' + JSON.stringify(err); callback(err, result); return; } //記錄資料變化記錄, var log = require('./serviceAdd_11.json'); //記錄新增資料後的返回資訊 dataChange.dbResult = JSON.stringify(result); //從資料庫裡獲取剛新增的資料 var traceGetNewData = { title:'獲取資料庫裡新增完成的資料', msg:'', startTime:time(), endTime:0, useTime:0, items:[] }; traceAddNewData.items.push(traceGetNewData); myQuery(tableInfo.sqlSelect,[result.insertId],traceGetNewData,function (err, result) { //獲取一條記錄完畢 //console.log('獲取更新資料的回撥result:' +JSON.stringify(result)); //console.log('獲取更新資料的回撥的trace:' +JSON.stringify(traceStartAddData)); //記錄資料變化日誌 var traceAddlog = { title:'記錄資料變化日誌', msg:'', startTime:time(), endTime:0, useTime:0, items:[] }; traceGetNewData.items.push(traceAddlog); //資料庫裡的新資料 dataChange.newDataJson = JSON.stringify(result); //目前為止的跟蹤記錄 dataChange.trace = JSON.stringify(info.trace); valuesParams = createParams(log.tableInfo,dataChange); //提交操作 myQuery(log.tableInfo.sql,valuesParams,traceAddlog,function (err, result){ //資料變化日誌回撥完畢 console.log('資料變化日誌回撥完畢:' +JSON.stringify(info.trace)); }); }); connection.end(); //回撥,不等資料變化的日誌了 callback(err, result); }); //console.log('呼叫結束等待結果'); //封裝資料庫操作,以及計時器 function myQuery(sql,vParme,traces,callback) { //console.log('myQuery的sql:' +sql); traces.msg += 'sql:'+sql; traces.msg += '_values:' + valuesParams; var conn = mysql.createConnection(cnString); conn.connect(); conn.query(sql,vParme,function (err, result) { //console.log('myQuery的回撥:' +err); traceStart.endTime = time(); traceStart.useTime = time() - traceStart.startTime; if(err){ console.log('[ERROR ] - ',err.message); traceStart.title += '——執行出錯:'+ err.message; traceStart.error = JSON.stringify(err) callback(err, result); return; } traceStart.title += '——成功!'; callback(err, result); }); conn.end(); //請求傳送完畢 //console.log('請求傳送完畢:'); traces.endTime = time(); traces.useTime = time() - traces.startTime; //記錄完成開始時間 var traceStart = { title:'請求傳送完畢,等待反饋', startTime:time(), endTime:0, useTime:0, items:[] }; traces.items.push(traceStart); } //拼接valuesParams function createParams(colInfo,data){ //console.log('開始拼接資料陣列'); var valuesParams = []; //資料變成陣列的形式 var colName = ""; for (var i=0 ;i<colInfo.column.length;i++) { colName = colInfo.column[i]; valuesParams.push(data[colName]); } return valuesParams; } //拼接sql function createSql2(){ sql = 'INSERT INTO ' +meta.tableName ; var cols = "(" + meta.primaryKey; var values = " VALUES(0"; var valuesParams = []; //拼接欄位名和引數 for (var key in meta.cols) { cols += ',' + key; values += ',?'; valuesParams.push(meta.cols[key]); } sql +=cols + ')' + values + ')'; console.log(sql); } };
跟蹤記錄
{ "title": "開始新增資料的服務", "msg": "", "startTime": 2950080457.323715, "endTime": 0, "useTime": 0, "items": [{ "title": "持久化之新增資料", "msg": "", "startTime": 2950080463.596571, "endTime": 0, "useTime": 0, "items": [{ "title": "獲取表資訊和資料、定義dataChange", "msg": "", "startTime": 2950080463.608944, "endTime": 2950080463.683611, "useTime": 0.08490705490112305, "items": [] }, { "title": "建立MySql物件、cnString、connection", "msg": "", "startTime": 2950080463.702811, "endTime": 2950080586.696783, "useTime": 122.99781227111816, "items": [] }, { "title": "準備傳送持久化請求,新增一條資料", "msg": "sql:INSERT INTO node_user(id,name,age) VALUES(0,?,?)_values:王五,45", "startTime": 2950080586.707023, "endTime": 2950080592.260519, "useTime": 5.556482791900635, "items": [{ "title": "請求傳送完畢,等待反饋——成功!", "startTime": 2950080592.271186, "endTime": 2950080612.196954, "useTime": 19.944968223571777, "items": [] }, { "title": "獲取資料庫裡新增完成的資料", "msg": "sql:SELECT * FROM node_user WHERE id = ?_values:王五,45", "startTime": 2950080615.264262, "endTime": 2950080616.479836, "useTime": 1.218986988067627, "items": [{ "title": "請求傳送完畢,等待反饋——成功!", "startTime": 2950080616.488796, "endTime": 2950080624.55792, "useTime": 8.072536945343018, "items": [] }, { "title": "記錄資料變化日誌", "msg": "", "startTime": 2950080625.123253, "endTime": 0, "useTime": 0, "items": [] }] }] }] }] }
我們在寫專案的時候,最鬱悶的就是,執行的時候報錯了,但是又不知道是哪一行出錯了。如果某個函式被呼叫好幾次,那麼就更頭疼了,到底是哪一次的呼叫出錯了呢?
有了這個跟蹤就能夠很方便的知道到底是執行到了哪裡出的錯誤,便於定位和修改。
ps:
這幾天寫程式碼的感受就是——糟糕透了。怪不得node都這麼多年了還沒火。真的太難駕馭了。