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

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

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

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);
        }
    });

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

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

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

回答
編輯回答
涼汐

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

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ā)錯誤
            }
        });
    });
}

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ā)錯誤
// transactionWithCommit(connection); // 正確的方法
write(connection);
2018年2月23日 12:40