Node.js MySQL错误处理
我已经阅读了一些在node.js中使用mysql的示例,并且对错误处理有疑问。
大多数示例都进行如下错误处理(为简便起见):
app.get('/countries', function(req, res) {    pool.createConnection(function(err, connection) {
        if (err) { throw err; }
        connection.query(sql, function(err, results) {
            if (err) { throw err; }
            connection.release();
            // do something with results
        });
    });
});
每次发生sql错误时,这都会导致服务器崩溃。我想避免这种情况并保持服务器运行。
我的代码是这样的:
app.get('/countries', function(req, res) {    pool.createConnection(function(err, connection) {
        if (err) {
            console.log(err);
            res.send({ success: false, message: 'database error', error: err });
            return;
        }
        connection.on('error', function(err) {
            console.log(err);
            res.send({ success: false, message: 'database error', error: err });
            return;
        });
        connection.query(sql, function(err, results) {
            if (err) {
                console.log(err);
                res.send({ success: false, message: 'query error', error: err });
                return;
            }
            connection.release();
            // do something with results
        });
    });
});
我不确定这是否是处理它的最佳方法。我也想知道connection.release()查询的err块中是否应该有一个。否则,连接可能会保持打开状态并随着时间的推移逐渐建立。
我习惯了Java try...catch...finally或try-with-
resources在这里可以“干净地”捕获任何错误并在最后关闭我的所有资源。有没有一种方法可以传播错误并在一处处理所有错误?
回答:
我决定使用es2017语法和Babel将其转换为Node7支持的es2016。
较新版本的Node.js无需转译即可支持此语法。
这是一个例子:
'use strict';const express = require('express');
const router = express.Router();
const Promise = require('bluebird');
const HttpStatus = require('http-status-codes');
const fs = Promise.promisifyAll(require('fs'));
const pool = require('./pool');     // my database pool module, using promise-mysql
const Errors = require('./errors'); // my collection of custom exceptions
////////////////////////////////////////////////////////////////////////////////
// GET /v1/provinces/:id
////////////////////////////////////////////////////////////////////////////////
router.get('/provinces/:id', async (req, res) => {
  try {
    // get a connection from the pool
    const connection = await pool.createConnection();
    try {
      // retrieve the list of provinces from the database
      const sql_p = `SELECT p.id, p.code, p.name, p.country_id
                     FROM provinces p
                     WHERE p.id = ?
                     LIMIT 1`;
      const provinces = await connection.query(sql_p);
      if (!provinces.length)
        throw new Errors.NotFound('province not found');
      const province = provinces[0];
      // retrieve the associated country from the database
      const sql_c = `SELECT c.code, c.name
                     FROM countries c
                     WHERE c.id = ?
                     LIMIT 1`;
      const countries = await connection.query(sql_c, province.country_id);
      if (!countries.length)
        throw new Errors.InternalServerError('country not found');
      province.country = countries[0];
      return res.send({ province });
    } finally {
      pool.releaseConnection(connection);
    }
  } catch (err) {
    if (err instanceof Errors.NotFound)
      return res.status(HttpStatus.NOT_FOUND).send({ message: err.message }); // 404
    console.log(err);
    return res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ error: err, message: err.message }); // 500
  }
});
////////////////////////////////////////////////////////////////////////////////
// GET /v1/provinces
////////////////////////////////////////////////////////////////////////////////
router.get('/provinces', async (req, res) => {
  try {
    // get a connection from the pool
    const connection = await pool.createConnection();
    try {
      // retrieve the list of provinces from the database
      const sql_p = `SELECT p.id, p.code, p.name, p.country_id
                     FROM provinces p`;
      const provinces = await connection.query(sql_p);
      const sql_c = `SELECT c.code, c.name
                     FROM countries c
                     WHERE c.id = ?
                     LIMIT 1`;
      const promises = provinces.map(async p => {
        // retrieve the associated country from the database
        const countries = await connection.query(sql_c, p.country_id);
        if (!countries.length)
          throw new Errors.InternalServerError('country not found');
        p.country = countries[0];
      });
      await Promise.all(promises);
      return res.send({ total: provinces.length, provinces });
    } finally {
      pool.releaseConnection(connection);
    }
  } catch (err) {
    console.log(err);
    return res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ error: err, message: err.message }); // 500
  }
});
////////////////////////////////////////////////////////////////////////////////
// OPTIONS /v1/provinces
////////////////////////////////////////////////////////////////////////////////
router.options('/provinces', async (req, res) => {
  try {
    const data = await fs.readFileAsync('./options/provinces.json');
    res.setHeader('Access-Control-Allow-Methods', 'HEAD,GET,OPTIONS');
    res.setHeader('Allow', 'HEAD,GET,OPTIONS');
    res.send(JSON.parse(data));
  } catch (err) {
    res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ error: err, message: err.message });
  }
});
module.exports = router;
使用async/ await伴随此try { try { } finally { } } catch { }
pattern品牌清洁的错误处理,在那里你可以收集和处理在一个地方所有的错误。无论如何,finally块都会关闭数据库连接。
您只需要确保自始至终都在兑现承诺。对于数据库访问,我使用promise-
mysql模块而不是普通mysql模块。对于其他所有内容,我都使用bluebird模块和promisifyAll()。
我还具有自定义的Exception类,可以在某些情况下抛出这些异常类,然后在catch块中检测到它们。根据可以在try块中引发哪些异常,我的catch块可能看起来像这样:
catch (err) {  if (err instanceof Errors.BadRequest)
    return res.status(HttpStatus.BAD_REQUEST).send({ message: err.message }); // 400
  if (err instanceof Errors.Forbidden)
    return res.status(HttpStatus.FORBIDDEN).send({ message: err.message }); // 403
  if (err instanceof Errors.NotFound)
    return res.status(HttpStatus.NOT_FOUND).send({ message: err.message }); // 404
  if (err instanceof Errors.UnprocessableEntity)
    return res.status(HttpStatus.UNPROCESSABLE_ENTITY).send({ message: err.message }); // 422
  console.log(err);
  return res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ error: err, message: err.message });
}
pool.js:
'use strict';const mysql = require('promise-mysql');
const pool = mysql.createPool({
  connectionLimit: 100,
  host: 'localhost',
  user: 'user',
  password: 'password',
  database: 'database',
  charset: 'utf8mb4',
  debug: false
});
module.exports = pool;
errors.js:
'use strict';class ExtendableError extends Error {
  constructor(message) {
    if (new.target === ExtendableError)
      throw new TypeError('Abstract class "ExtendableError" cannot be instantiated directly.');
    super(message);
    this.name = this.constructor.name;
    this.message = message;
    Error.captureStackTrace(this, this.contructor);
  }
}
// 400 Bad Request
class BadRequest extends ExtendableError {
  constructor(m) {
    if (arguments.length === 0)
      super('bad request');
    else
      super(m);
  }
}
// 401 Unauthorized
class Unauthorized extends ExtendableError {
  constructor(m) {
    if (arguments.length === 0)
      super('unauthorized');
    else
      super(m);
  }
}
// 403 Forbidden
class Forbidden extends ExtendableError {
  constructor(m) {
    if (arguments.length === 0)
      super('forbidden');
    else
      super(m);
  }
}
// 404 Not Found
class NotFound extends ExtendableError {
  constructor(m) {
    if (arguments.length === 0)
      super('not found');
    else
      super(m);
  }
}
// 409 Conflict
class Conflict extends ExtendableError {
  constructor(m) {
    if (arguments.length === 0)
      super('conflict');
    else
      super(m);
  }
}
// 422 Unprocessable Entity
class UnprocessableEntity extends ExtendableError {
  constructor(m) {
    if (arguments.length === 0)
      super('unprocessable entity');
    else
      super(m);
  }
}
class InternalServerError extends ExtendableError {
  constructor(m) {
    if (arguments.length === 0)
      super('internal server error');
    else
      super(m);
  }
}
module.exports.BadRequest = BadRequest;
module.exports.Unauthorized = Unauthorized;
module.exports.Forbidden = Forbidden;
module.exports.NotFound = NotFound;
module.exports.Conflict = Conflict;
module.exports.UnprocessableEntity = UnprocessableEntity;
module.exports.InternalServerError = InternalServerError;
以上是 Node.js MySQL错误处理 的全部内容, 来源链接: utcz.com/qa/419417.html







