鍍金池/ 問答/數(shù)據(jù)庫  HTML/ Node mysql 程序運(yùn)行一段時(shí)間后,讀寫數(shù)據(jù)庫出現(xiàn)異常?

Node mysql 程序運(yùn)行一段時(shí)間后,讀寫數(shù)據(jù)庫出現(xiàn)異常?

程序使用 Node 編寫,后端數(shù)據(jù)庫為 MySQL,提供 APP 后端 API 及 socket 連接服務(wù)。目前單實(shí)例部署,實(shí)例內(nèi)使用一個(gè) MySQL 連接。服務(wù)初期工作一切正常,隨著服務(wù)時(shí)間變長(zhǎng)(一天到一周不等),某個(gè)時(shí)間點(diǎn),一個(gè) API 調(diào)用會(huì)發(fā)生失敗,發(fā)生該錯(cuò)誤之后,后續(xù)的所有數(shù)據(jù)庫讀寫操作都會(huì)失敗。API 服務(wù)代碼出錯(cuò)的原因是:向 MySQL 插入一條記錄失敗,我在關(guān)鍵代碼處插入了一些代碼:

self.conn.query(sql, function(err, res, fields){
        if(err){
            callback && callback(ERRCODE.MYSQL.code, err);
        }else{
            if (!res.insertId) {
                logger.error('activity.insertActivitySpeaker: insertId undefined');
            } else {
                logger.info('success: activity.insertActivitySpeaker: insertId %s', res.insertId);
            }
            callback && callback(0, res);
        }
    });

比較難理解的是,插入操作失敗時(shí),代碼

logger.info('success: activity.insertActivitySpeaker: insertId %s', res.insertId);

仍被執(zhí)行,且打印了一個(gè)正常的 id(自增),但是 MySQL binlog 中并無相應(yīng)的操作日志,且最終數(shù)據(jù)庫里也查不到 id 對(duì)應(yīng)的那條記錄。目前猜測(cè)是服務(wù)長(zhǎng)時(shí)間運(yùn)行或代碼邏輯漏洞導(dǎo)致 MySQL 連接異常:向 MySQL 嘗試寫入時(shí),可以獲得一個(gè)寫入 id,但最終的寫入操作未執(zhí)行成功,而從數(shù)據(jù)庫讀取的操作,返回的數(shù)據(jù)都是空。不知朋友們有沒有遇到過類似問題,給些排查建議,萬分感謝。

回答
編輯回答
涼汐

問題原因是使用事務(wù)時(shí),缺少 rollback 或 commit,使用以下代碼可穩(wěn)定復(fù)現(xiàn)這個(gè)錯(cuò)誤:

let mysql = require("mysql");

function createConn() {
    return mysql.createConnection({
        host     : '192.168.1.100',
        user     : 'yangqiang',
        password : '123456',
        database : 'node_mysql_demo'
    });
}

function transactionWithoutCommit(conn) {
    conn.beginTransaction(function (err) {
        if (err) {
            throw err;
        }
        conn.query('SELECT * from user where name="jonny"', function (error, results, fields) {
            if (error) {
                return conn.rollback(function () {
                    throw error;
                })
            } else {
                // 缺少 commit,引發(fā)錯(cuò)誤
            }
        });
    });
}

function transactionWithCommit(conn) {
    conn.beginTransaction(function (err) {
        if (err) {
            throw err;
        }
        conn.query('SELECT * from user where name="jonny"', function (error, results, fields) {
            if (error) {
                return conn.rollback(function () {
                    throw error;
                })
            } else {
                conn.commit(function (err) {
                    if (err) {
                        return conn.rollback(function(){ throw err;})
                    } else {
                        console.log('transaction committed');
                    }
                });
            }
        });
    });
}

function write(conn) {
    conn.query('INSERT INTO user (name) VALUES ("Mei");', function (error, results, fields) {
        if (error) throw error;
        console.log(JSON.stringify(results));
    });
}


var connection = createConn();
connection.connect();

transactionWithoutCommit(connection); // 引發(fā)錯(cuò)誤
// transactionWithCommit(connection); // 正確的方法
write(connection);
2018年2月23日 12:40