I’ve decided to handle it using es2017 syntax and Babel to transpile down to es2016, which Node 7 supports.
Newer versions of Node.js support this syntax without transpiling.
Here is an example:
'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;
Using async
/await
along with this try { try { } finally { } } catch { } pattern
makes for clean error handling, where you can collect and deal with all your errors in one place. The finally block closes the database connection no matter what.
You just have to make sure you’re dealing with promises all the way through. For database access, I use the promise-mysql
module instead of plain mysql
module. For everything else, I use the bluebird
module and promisifyAll()
.
I also have custom Exception classes that I can throw under certain circumstances and then detect those in the catch block. Depending on which exceptions can get thrown in the try block, my catch block might look something like this:
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);
}
}
// 500 Internal Server Error
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;
This is a function to return available pool upon successful MySQL connection. So before I proceed with any query, I’ll await this function to check whether connection is OK. This will not crash the server even if there’s no connection to MySQL.
connect: function ()
{
return new Promise((resolve, reject) => {
let pool = Mysql.createPool({
connectionLimit: config.mysql.connectionLimit,
host: config.mysql.host,
user: config.mysql.user,
password: config.mysql.password,
database: config.mysql.database
});
pool.getConnection((err, con) =>
{
try
{
if (con)
{
con.release();
resolve({"status":"success", "message":"MySQL connected.", "con":pool});
}
}
catch (err)
{
reject({"status":"failed", "error":`MySQL error. ${err}`});
}
resolve({"status":"failed", "error":"Error connecting to MySQL."});
});
});
}
MySQL package used: https://www.npmjs.com/package/mysql
Native Promise async/await ES2017
Unified error API for node.js SQL DB drivers
This project is an attempt to create a unified API for node.js SQL DB driver errors. Each driver
throws their own kind of errors and libraries like knex, Bookshelf and objection.js simply
pass these errors through. It’s usually very difficult to reason with these errors. This
library wraps those errors to error classes that are the same for all drivers. The wrapped
error classes also expose useful information about the errors.
NOTE: Only MySQL, Sqlite3, MSSQL and PostgreSQL are officially supported (tested).
Contributions and suggestions are most welcome
If you have an idea for an error we should handle, please open an issue and we’ll see what we can do to add it.
Usage
const { wrapError, DBError, UniqueViolationError, NotNullViolationError } = require('db-errors'); function errorHandler(err) { // wrapError function takes any error and returns a DBError subclass instance if // the input was an error thrown by the supported database drivers. Otherwise // the input error is returned. err = wrapError(err); if (err instanceof UniqueViolationError) { console.log( `Unique constraint ${err.constraint} failed for table ${err.table} and columns ${err.columns}` ); } else if (err instanceof NotNullViolationError) { console.log(`Not null constraint failed for table ${err.table} and column ${err.column}`); } else if (err instanceof DBError) { console.log(`Some unknown DB error ${dbError.nativeError}`); } }
API
DBError
class DBError extends Error { // The error thrown by the database client. nativeError: Error; }
Base class for all errors.
ConstraintViolationError
class ConstraintViolationError extends DBError { // No own properties. }
A base class for all constraint violation errors
UniqueViolationError
class UniqueViolationError extends ConstraintViolationError { // The columns that failed. // // Available for: postgres, sqlite columns: string[]; // The table that has the columns. // // Available for: postgres, sqlite table: string; // The constraint that was violated. // // Available for: postgres, mysql constraint: string; }
NotNullViolationError
class NotNullViolationError extends ConstraintViolationError { // The column that failed. // // Available for: postgres, sqlite, mysql column: string; // The table that has the columns. // // Available for: postgres, sqlite table: string; }
ForeignKeyViolationError
class ForeignKeyViolationError extends ConstraintViolationError { // The table that has the foreign key. // // Available for: postgres, mysql table: string; // The constraint that was violated. // // Available for: postgres, mysql constraint: string; }
CheckViolationError
// This is not available for MySql since MySql doesn't have check constraints. class CheckViolationError extends ConstraintViolationError { // The table that has the check constraint. // // Available for: postgres table: string; // The constraint that was violated. // // Available for: postgres constraint: string; }
DataError
// Invalid data (string too long, invalid date etc.) // // NOTE: SQLite uses dynamic typing and doesn't throw this error. class DataError extends DBError { // There is no easy way to parse data from these kind // of errors. }
Development setup
Run the following commands in the repo root:
docker-compose up node setup-test-db.js
Run tests:
Node.js с MySQL
Последнее обновление 29 марта 2019 08:39:27 (UTC / GMT +8 часов)
script1adsense2code
script1adsense3code
node-mysql: модуль node.js, реализующий протокол MySQL
Это драйвер node.js для mysql. Он написан на JavaScript, не требует компиляции. Он предоставляет все наиболее все соединения / запросы из MySQL. Node-mysql , вероятно, является одним из лучших модулей, используемых для работы с базой данных MySQL, и этот модуль активно поддерживается.
Мы предполагаем, что вы уже установили MySQL и node.js в среде Windows или Linux.
Вот пример получения первой строки из таблицы ’employee’, принадлежащей базе данных ‘ hr ‘:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'datasoft123',
database : 'hr'
});
connection.connect();
connection.query('SELECT * FROM employees', function(err, rows, fields)
{
if (err) throw err;
console.log(rows[0]);
});
connection.end();
Выход :
{EMPLOYEE_ID: 100, FIRST_NAME: «Стивен», LAST_NAME: "Король", EMAIL: ' [электронная почта защищена] ', PHONE_NUMBER: '515.123.4567', HIRE_DATE: ср. 17 июня 1987 г. 00:00:00 GMT + 0530 (стандартное время Индии), JOB_ID: «AD_PRES», Заработная плата: 24000, COMMISSION_PCT: 0, MANAGER_ID: 0, DEPARTMENT_ID: 90}
Из приведенного выше примера вы можете узнать, как создать новое соединение и закрыть соединение.
Содержание:
- Установите MySQL node.js драйвер
- Создание и разрыв соединений, варианты подключения
- Обработка ошибок
- Параметры SSL
- Объединение соединений, опций и событий
- Экранирование значений запроса, идентификаторов
- Подготовка запросов
- Хранимые процедуры
- присоединяется
- операции
- Таймауты
Установите MySQL node.js драйвер
$ npm install mysql
Вы можете установить последнюю версию с Github, чтобы проверить, работает ли исправление. В этом случае используйте следующую команду:
$ npm install felixge/node-mysql
Создать соединение
Вот код для установки соединения:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'example.org',
user : 'root',
password : 'datasoft123'
});
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
Вот еще один способ установить соединение, вызвав запрос:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'datasoft123'
});
connection.query('SELECT 1', function(err, rows) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected!');
});
Вариант подключения
название | Описание |
---|---|
хозяин | Имя хоста базы данных. По умолчанию это localhost. |
порт | Номер порта для подключения. По умолчанию 3306. |
localAddress | Исходный IP-адрес для использования для соединения TCP. (Необязательный) |
socketPath | Путь к сокету домена Unix для подключения. При использовании хост и порт игнорируются. |
пользователь | Пользователь MySQL для аутентификации как. |
пароль | Пароль этого пользователя MySQL. |
база данных | Имя базы данных, используемой для этого соединения (необязательно). |
кодировок | Кодировка для связи. Это называется «сопоставление» на уровне SQL MySQL (например, utf8_general_ci). Если указан набор символов уровня SQL (например, utf8mb4), то используется сопоставление по умолчанию для этого набора символов. По умолчанию: «UTF8_GENERAL_CI» |
часовой пояс | Часовой пояс используется для хранения местных дат. По умолчанию: «локальный». |
ConnectTimeout | Миллисекунды до истечения времени ожидания при первоначальном подключении к серверу MySQL. (По умолчанию: 10 секунд) |
stringifyObjects | Stringify объекты вместо преобразования в значения. Смотрите выпуск № 501. По умолчанию: «false» |
insecureAuth | Разрешить подключение к экземплярам MySQL, которые запрашивают старый (небезопасный) метод аутентификации. (По умолчанию: false) |
напечатанный материал | Определяет, следует ли преобразовывать значения столбцов в собственные типы JavaScript. (По умолчанию: true) |
queryFormat | Пользовательский формат запроса. Смотрите пользовательский формат. |
supportBigNumbers | При работе с большими числами (столбцы BIGINT и DECIMAL) в базе данных вы должны включить эту опцию (по умолчанию: false). |
bigNumberStrings | Включение и supportBigNumbers, и bigNumberStrings заставляет большие числа (столбцы BIGINT и DECIMAL) всегда возвращаться как объекты JavaScript String (по умолчанию: false). Включение supportBigNumbers, но с отключением bigNumberStrings возвращает большие числа в виде объектов String, только если они не могут быть точно представлены с помощью объектов JavaScript Number (что происходит, когда они превышают диапазон [-2 ^ 53, + 2 ^ 53]), в противном случае они будут возвращены Количество объектов. Эта опция игнорируется, если supportBigNumbers отключен. |
dateStrings | Принудительно возвращать типы даты (TIMESTAMP, DATETIME, DATE) в виде строк, а не раздувать в объекты JavaScript Date. (По умолчанию: false) |
отлаживать | Выводит детали протокола на стандартный вывод. (По умолчанию: false) |
след | Генерирует трассировки стека при ошибке, чтобы включить сайт вызова входа в библиотеку («длинные трассировки стека»). Небольшое снижение производительности для большинства звонков. По умолчанию это правда. |
multipleStatements | Разрешить несколько операторов MySQL на запрос. Будьте осторожны с этим, он подвергает вас атакам SQL-инъекций. (По умолчанию: false) |
флаги | Список используемых флагов подключения, отличных от заданных по умолчанию. Также возможно занести в черный список по умолчанию. Для получения дополнительной информации, проверьте Флаги подключения. |
SSL | объект с параметрами ssl или строка, содержащая имя профиля ssl. Смотрите параметры SSL. |
Примечание. Сначала выполняется попытка анализа значений запроса как JSON, а в случае неудачи предполагается, что это строки в виде открытого текста.
Завершение соединения
Есть два способа разорвать соединение:
- метод end ()
- метод destroy ()
Вы можете разорвать соединение, вызвав метод end ():
connection.end(function(err) {
// The connection is terminated now
});
Это будет гарантировать, что все ранее поставленные в очередь запросы все еще перед отправкой пакета COM_QUIT на сервер MySQL. Если перед отправкой пакета COM_QUIT происходит фатальная ошибка, обратному вызову будет предоставлен аргумент err, но соединение будет разорвано независимо от этого.
метод destroy ():
Этот метод завершает соединение немедленно. Кроме того, destroy () гарантирует, что больше никаких событий или обратных вызовов не будет запущено для соединения.
connection.destroy();
В отличие от end () метод destroy () не принимает аргумент обратного вызова.
Переключение пользователей / изменение состояния соединения:
MySQL предлагает команду changeUser, которая позволяет вам изменять текущего пользователя и другие аспекты соединения без выключения основного сокета:
connection.changeUser({user : 'user2'}, function(err) {
if (err) throw err;
});
Доступные варианты:
название | Описание |
---|---|
пользователь | Имя нового пользователя (по умолчанию предыдущее). |
пароль | Пароль нового пользователя (по умолчанию предыдущий). |
кодировок | Новая кодировка (по умолчанию предыдущая). |
база данных | Новая база данных (по умолчанию предыдущая). |
Иногда полезным побочным эффектом этой функциональности является то, что эта функция также сбрасывает любое состояние соединения (переменные, транзакции и т. Д.).
Ошибки, обнаруженные во время этой операции, рассматриваются модулем как фатальные ошибки подключения.
Обработка ошибок
В этом модуле есть несколько вариантов обработки ошибок:
Все ошибки, созданные этим модулем, являются экземплярами объекта JavaScript Error. Кроме того, они имеют два свойства:
- код ошибки:
- Ошибка сервера MySQL (например, «ER_ACCESS_DENIED_ERROR»)
- Ошибка node.js (например, «ECONNREFUSED»)
- Внутренняя ошибка (например, ‘PROTOCOL_CONNECTION_LOST’)
- err.fatal: Boolean, указывающий, является ли эта ошибка терминальной для объекта соединения.
Фатальные ошибки распространяются (чтобы вызвать умножение на любой процесс) на все ожидающие обратные вызовы. В приведенном ниже примере фатальная ошибка вызывается попыткой ввести недопустимое имя пользователя. Поэтому в следующем примере объект ошибки распространяется на оба ожидающих обратных вызова:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'roott',
password : 'datasoft123',
});
connection.connect(function(err) {
console.log(err.code);
console.log(err.fatal);
});
connection.query('SELECT 1', function(err) {
console.log(err.code);
console.log(err.fatal);
});
Выход :
ER_ACCESS_DENIED_ERROR правда ER_ACCESS_DENIED_ERROR правда
В этом примере фатальная ошибка вызвана недопустимым пользователем.
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'roott',
password : 'datasoft123'
});
connection.query('SELECT 1', function(err){
if (err){
console.log(err.code);
console.log(err.fatal);
}
});
connection.end();
Выход :
E: / nodejs> узел test.js
ER_ACCESS_DENIED_ERROR
правда
Нормальные ошибки делегируются только обратному вызову, которому они принадлежат. В следующем примере только первый обратный вызов получает ошибку (неправильное имя БД), второй запрос работает как положено:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'datasoft123',
});
//Wrong database name
connection.query('USE kkk', function(err, rows) {
console.log(err.code); // 'ER_BAD_DB_ERROR'
});
connection.query('SELECT 1', function(err, rows) {
// null
console.log(err);
// length of the row 1
console.log(rows.length);
});
Сервер отключается:
Вы можете потерять соединение с сервером MySQL из-за проблем с сетью, истечения времени ожидания сервера, перезапуска сервера или сбоя. Все эти события считаются фатальными ошибками и имеют код ошибки err.code = ‘PROTOCOL_CONNECTION_LOST’. См. Раздел Обработка ошибок для получения дополнительной информации.
Переподключение соединения выполняется путем установления нового соединения. После завершения существующий объект подключения не может быть повторно подключен по проекту.
При использовании пула отключенные соединения будут удаляться из пула, освобождая место для нового соединения, которое будет создано при следующем вызове getConnection.
Параметры SSL
Параметр ssl в параметрах подключения принимает строку или объект. Когда задана строка, он использует один из предопределенных включенных профилей SSL. Следующие профили включены:
- «Amazon RDS»: этот профиль предназначен для подключения к серверу Amazon RDS и содержит приблизительно https://rds.amazonaws.com/doc/rds-ssl-ca-cert.pem
При подключении к другим серверам вам нужно будет предоставить объект параметров в том же формате, что и crypto.createCredentials. Обратите внимание, что аргументы предполагают строку сертификата, а не имя файла сертификата. Вот простой пример:
var connection = mysql.createConnection({
host : 'localhost',
ssl : {
ca : fs.readFileSync(__dirname + '/mysql-ca.crt')
}
});
Вы также можете подключиться к серверу MySQL без надлежащего предоставления соответствующего CA для доверия. Вы не должны этого делать.
var connection = mysql.createConnection({
host : 'localhost',
ssl : {
// DO NOT DO THIS
// set up your ca correctly to trust the connection
rejectUnauthorized: false
}
});
var connection = mysql.createConnection({
host : 'localhost',
ssl : {
// DO NOT DO THIS
// set up your ca correctly to trust the connection
rejectUnauthorized: false
}
});
Пул соединения
Пул соединений — это кэш соединений с базой данных, который поддерживается для повторного использования, когда требуются будущие запросы к базе данных. Пулы соединений используются для повышения производительности выполнения команд в базе данных.
Используйте бассейн напрямую.
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'localhost',
user : 'root',
password : 'datasoft123'
});
pool.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
if (err) throw err;
console.log('The solution is: ', rows[0].solution);
});
Когда вы закончите с подключением, просто вызовите connection.release (), и подключение вернется в пул, готовый к повторному использованию кем-либо еще.
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'localhost',
user : 'root',
password : 'datasoft123',
database : 'hr'
});
pool.getConnection(function(err, connection) {
// Use the connection
connection.query( 'SELECT * from employees', function(err, rows) {
// And done with the connection.
console.log(rows[0]);
connection.release();
// Don't use the connection here, it has been returned to the pool.
});
});
Если вы хотите закрыть соединение и удалить его из пула, используйте вместо него connection.destroy (). В следующий раз пул создаст новое соединение.
Закрытие всех соединений в пуле
Когда вы закончите использовать пул, вы должны завершить все соединения, иначе цикл событий Node.js останется активным, пока соединения не будут закрыты сервером MySQL. Метод end принимает необязательный обратный вызов, который вы можете использовать, чтобы знать, как только все соединения завершены. Соединения завершаются изящно, поэтому все ожидающие запросы будут по-прежнему завершаться, а время завершения пула будет различным. После того как pool.end () был вызван, pool.getConnection и другие операции больше не могут выполняться
Варианты бассейна
Пул поддерживает все варианты нормального подключения. Кроме того, здесь есть несколько дополнительных опций:
название | Описание |
---|---|
acquireTimeout | Миллисекунды до истечения времени ожидания во время получения соединения. Это немного отличается от connectTimeout, потому что получение подключения к пулу не всегда связано с установлением соединения. (По умолчанию: 10 секунд) |
waitForConnections | Определяет действие пула, когда нет доступных подключений и достигнут предел. Если true, пул будет ставить в очередь запрос на подключение и вызывать его, когда он станет доступным. Если false, пул немедленно перезвонит с ошибкой. (По умолчанию: true) |
connectionLimit | Максимальное количество соединений, создаваемых за один раз. (По умолчанию: 10) |
queueLimit | Максимальное количество запросов на подключение, которые пул поставит в очередь перед возвратом ошибки из getConnection. Если установлено значение 0, количество запросов на подключение в очереди не ограничено. (По умолчанию: 0) |
Мероприятия в бассейне
соединение :
Пул выдаст событие соединения, когда в пуле будет установлено новое соединение. Если вам нужно установить переменные сеанса в соединении до того, как оно будет использовано, вы можете прослушать событие соединения.
pool.on('connection', function (connection) {
connection.query('SET SESSION auto_increment_increment=1')
});
ставить в очередь :
Пул отправит событие enqueue, когда обратный вызов был поставлен в очередь для ожидания доступного соединения.
pool.on('enqueue', function () {
console.log('Waiting for available connection slot');
});
Экранирование значений запроса
SQL-инъекция — это метод (как и другие механизмы веб-атак) для атаки на приложения, управляемые данными. Эта атака может обойти брандмауэр и повлиять на полностью исправленную систему. Атакующий использует преимущество плохо отфильтрованных или неправильно экранированных символов, встроенных в операторы SQL, при разборе переменных данных из пользовательского ввода. Злоумышленник вводит произвольные данные, чаще всего запрос к базе данных, в строку, которая в конечном итоге выполняется базой данных через веб-приложение (например, форму входа в систему).
Чтобы избежать атак SQL-инъекций, вы всегда должны избегать любых предоставленных пользователем данных, прежде чем использовать их в запросе SQL. Вы можете сделать это с помощью методов connection.escape () или pool.escape ():
var userId = 'некоторое значение, предоставленное пользователем'; var sql = 'SELECT * FROM пользователей WHERE id =' + connection.escape (userId); connection.query (sql, function (err, results) { // ... });
В качестве альтернативы вы можете использовать? символы в качестве заполнителей для значений, которые вы хотели бы экранировать следующим образом:
connection.query ('SELECT * FROM users WHERE id =?', [userId], function (err, results) { // ... });
Различные типы значений экранируются по-разному, вот как:
- Числа остались нетронутыми
- Булевы значения преобразуются в истинные / ложные строки
- Объекты даты преобразуются в строки «ГГГГ-мм-дд ЧЧ: ii: сс»
- Буферы преобразуются в шестнадцатеричные строки, например, X’0fa5 ‘
- Строки благополучно экранированы
- Массивы превращаются в список, например [‘a’, ‘b’] превращается в ‘a’, ‘b’
- Вложенные массивы превращаются в сгруппированные списки (для массовых вставок), например [[‘a’, ‘b’], [‘c’, ‘d’]] превращаются в (‘a’, ‘b’), (‘c ‘,’ d ‘)
- Объекты превращаются в пары ключ = ‘val’. Вложенные объекты преобразуются в строки.
- undefined / null преобразуются в NULL
- NaN / Infinity остаются как есть. MySQL не поддерживает их, и попытка вставить их как значения вызовет ошибки MySQL, пока они не реализуют поддержку.
Вот пример оператора INSERT INTO:
var post = {id: 1, title: 'Hello MySQL'}; var query = connection.query ('INSERT INTO posts SET?', post, function (err, result) { // Аккуратно! }); console.log (query.sql); // INSERT INTO посты SET `id` = 1,` title` = 'Hello MySQL'
Вы также можете напрямую использовать функцию escape, см. Следующий пример:
var query = "SELECT * FROM сообщений WHERE title =" + mysql.escape ("Hello MySQL"); console.log (запрос); // ВЫБРАТЬ * ИЗ ПОЛОЖЕНИЙ, ГДЕ title = 'Hello MySQL'
Экранирующие идентификаторы запросов
Поскольку идентификатор SQL (имя базы данных / таблицы / столбца) предоставляется пользователем, вы должны экранировать его с помощью mysql.escapeId (идентификатор), connection.escapeId (идентификатор) или pool.escapeId (идентификатор), например так:
var sorter = 'date'; var sql = 'SELECT * FROM сообщений ORDER BY' + connection.escapeId (сортировщик); connection.query (sql, function (err, results) { // ... });
Он также поддерживает добавление квалифицированных идентификаторов. Это избежит обеих частей.
var sorter = 'date'; var sql = 'SELECT * FROM сообщений ORDER BY' + connection.escapeId ('posts.' + sorter); connection.query (sql, function (err, results) { // ... });
В качестве альтернативы вы можете использовать ?? символы в качестве заполнителей для идентификаторов, которые вы хотели бы экранировать следующим образом:
var userId = 1; var columns = ['username', 'email']; var query = connection.query ('SELECT ?? FROM ?? WHERE id =?', [столбцы, 'users', userId], function (err, results) { // ... }); console.log (query.sql); // ВЫБИРАЕМ `username`,` email` ОТ `users` WHERE id = 1
Примечание. Последняя последовательность символов является экспериментальной, и ее синтаксис может измениться.
Когда вы передаете Object в .escape () или .query (), .escapeId () используется, чтобы избежать внедрения SQL в ключи объекта.
Подготовка запросов
MySQL 5.6 обеспечивает поддержку подготовленных операторов на стороне сервера. Эта поддержка использует преимущества эффективного двоичного протокола клиент-сервер, доступного начиная с MySQL 4.1. Вы можете использовать mysql.format для подготовки запроса с несколькими точками вставки, используя правильное экранирование для идентификаторов и значений. Вот простой пример этого:
var sql = "SELECT * FROM ?? WHERE ?? =?"; var insertts = ['users', 'id', userId]; sql = mysql.format (sql, вставки);
После этого у вас есть действительный, экранированный запрос, который вы затем можете безопасно отправить в базу данных. Это полезно, если вы хотите подготовить запрос перед его отправкой в базу данных. Поскольку mysql.format предоставляется из SqlString.format, у вас также есть возможность (но не обязательно) передавать stringifyObject и часовой пояс, что позволяет вам предоставлять пользовательские средства для преобразования объектов в строки, а также для конкретного местоположения / timezone- Дата в курсе.
Пользовательский формат:
Если вы предпочитаете использовать другой тип escape-формата запроса, есть опция конфигурации соединения, которую вы можете использовать для определения функции пользовательского формата. Вы можете получить доступ к объекту подключения, если хотите использовать встроенную функцию .escape () или любую другую функцию подключения.
Вот пример того, как реализовать другой формат:
connection.config.queryFormat = function (query, values) { if (! values) return query; return query.replace (//: (/ w +) / g, function (txt, key) { if (values.hasOwnProperty (key)) { вернуть this.escape (values [key]); } вернуть текст; } .Bind (это)); }; connection.query («ОБНОВЛЕНИЕ постов SET title =: title», {title: «Hello MySQL»});
Получение идентификатора вставленной строки:
Если вы вставляете строку в таблицу с первичным ключом с автоматическим приращением, вы можете получить идентификатор вставки следующим образом:
connection.query ('INSERT INTO posts SET?', {title: 'test'}, function (err, result) { if (err) throw err; console.log (result.insertId); });
При работе с большими числами (выше предела точности чисел в JavaScript) следует рассмотреть возможность включения опции поддержки BigNumbers, чтобы иметь возможность считывать идентификатор вставки в виде строки, в противном случае он будет выброшен.
Эта опция также требуется при получении больших чисел из базы данных, в противном случае вы получите значения, округленные до сотен или тысяч из-за предела точности.
Получение количества затронутых рядов.
Вы можете получить количество затронутых строк из оператора вставки, обновления или удаления.
«changeRows» отличается от «disabledRows» тем, что не учитывает обновленные строки, значения которых не были изменены.
connection.query ('УДАЛИТЬ ИЗ ПОЛОЖЕНИЙ, ГДЕ title = "false"', function (err, result) { if (err) throw err; console.log («удалено» + result.afferedRows + «строки»); })
Получение идентификатора соединения
Вы можете получить идентификатор соединения MySQL («идентификатор потока») данного соединения, используя свойство threadId.
connection.connect (function (err) { if (err) throw err; console.log ('подключен как id' + connection.threadId); });
Выполнение запросов параллельно:
Протокол MySQL является последовательным, это означает, что вам нужно несколько соединений для параллельного выполнения запросов. Вы можете использовать Пул для управления соединениями, один простой подход — создать одно соединение для каждого входящего HTTP-запроса.
Потоковые строки запроса
Иногда вы можете выбрать большое количество строк и обрабатывать каждую из них по мере их поступления. Это можно сделать так:
var query = connection.query ('SELECT * FROM posts'); запрос .on ('error', function (err) { // Обработка ошибки, после этого также будет выдано событие 'end' }) .on ('fields', function (fields) { // поля пакетов для последующих строк }) .on ('результат', функция (строка) { // Приостановка соединения полезна, если ваша обработка включает ввод / вывод connection.pause (); processRow (row, function () { connection.resume (); }); }) .on ('end', function () { // все строки получены });
Обратите внимание на несколько вещей о примере выше:
- Обычно вы хотите получить определенное количество строк, прежде чем начинать регулировать соединение с помощью pause (). Это число будет зависеть от количества и размера ваших строк.
- pause () / resume () работают с нижележащим сокетом и парсером. Вам гарантировано, что после вызова pause () больше не будет событий ‘result’.
- Вы НЕ ДОЛЖНЫ предоставлять обратный вызов метода query () при потоковой передаче строк.
- Событие ‘result’ будет запускаться для обеих строк, а также для пакетов OK, подтверждая успешность запроса INSERT / UPDATE.
Кроме того, вам может быть интересно узнать, что в настоящее время невозможно потоковое воспроизведение отдельных столбцов строк, они всегда будут полностью буферизованы. Если у вас есть хороший вариант использования для потоковой передачи больших полей в MySQL и из нее, я бы хотел узнать ваши мнения и предложения по этому вопросу.
Несколько запросов операторов:
Поддержка нескольких операторов отключена по соображениям безопасности (она допускает атаки с использованием SQL-инъекций, если значения не экранированы должным образом). Чтобы использовать эту функцию, вы должны включить ее для вашего подключения:
var connection = mysql.createConnection ({multipleStatements: true});
После включения вы можете выполнять несколько запросов операторов, как и любой другой запрос:
connection.query ('SELECT 1; SELECT 2', функция (ошибка, результаты) { if (err) throw err; // `results` - массив с одним элементом для каждого оператора в запросе: console.log (результаты [0]); // [{1: 1}] console.log (результаты [1]); // [{2: 2}] });
Кроме того, вы также можете передавать результаты нескольких запросов операторов:
var query = connection.query ('SELECT 1; SELECT 2'); запрос .on ('fields', function (fields, index) { // поля для строк результата, которые следуют }) .on ('результат', функция (строка, индекс) { // индекс ссылается на оператор, которому принадлежит этот результат (начинается с 0) });
Если один из операторов в вашем запросе вызывает ошибку, результирующий объект Error содержит свойство err.index, которое сообщает вам, какой оператор вызвал его. MySQL также прекратит выполнение любых оставшихся операторов при возникновении ошибки.
Обратите внимание, что интерфейс для потоковой передачи запросов нескольких операторов является экспериментальным, и я с нетерпением жду обратной связи по нему.
Хранимые процедуры
Вы можете вызывать хранимые процедуры из ваших запросов, как и с любым другим драйвером mysql. Вот оригинальный код процедуры:
РАЗДЕЛИТЕЛЬ $$ CREATE PROCEDURE my_procedure_User_Variables () НАЧАТЬ SET @x = 15; SET @y = 10; SELECT @x, @y, @ [электронная почта защищена] ; END $$
Вывод, когда он был выполнен в MySQL:
mysql> CALL my_procedure_User_Variables (); + ------ + ------ + ------- + | @x | @y | @ [электронная почта защищена] | + ------ + ------ + ------- + | 15 | 10 | 5 | + ------ + ------ + ------- + 1 строка в наборе (0,04 с) Запрос в порядке, затронуто 0 строк (0,05 с)
Теперь вызовите хранимую процедуру из node.js:
var mysql = require ('mysql'); var connection = mysql.createConnection ({ хост: 'localhost', пользователь: 'root', пароль: 'datasoft123', база данных: 'час' }); connection.connect (); connection.query ("CALL my_procedure_User_Variables ();", функция (ошибки, строки) { if (err) throw err; console.log (строки); }); connection.end ();
Выход :
[[{'@x': 15, '@y': 10, '@ [электронная почта защищена] ': 5}], {fieldCount: 0, ctedRows: 0, insertId: 0, serverStatus: 2, warningCount: 0, сообщение: '', протокол41: верно, changeRows: 0}]
присоединяется
Вы можете вызывать JOINS из ваших запросов, как и с любым другим драйвером mysql. Вот пример:
Напишите запрос, чтобы отобразить идентификатор отдела, название отдела и имя руководителя. Смотрите базу данных « hr ».
var mysql = require ('mysql'); var connection = mysql.createConnection ({ хост: 'localhost', пользователь: 'root', пароль: 'datasoft123', база данных: 'час' }); connection.connect (); connection.query ("SELECT d.department_id, d.department_name, e.manager_id, e.first_name ОТ департаментов d ВНУТРЕННИЕ СОЕДИНИТЕЛИ сотрудников e ON (d.manager_id = e.employee_id); ", функция (ошибки, строки) { if (err) throw err; console.log (строки); }); connection.end ();
Выход :
[{Department_id: 10, название отдела: «Администрация», manager_id: 101, имя: Дженнифер, {Department_id: 20, название отдела: «Маркетинг», manager_id: 100, first_name: 'Michael'}, {Department_id: 30, название отдела: 'Закупки', manager_id: 100, first_name: 'Den'}, {Department_id: 40, название отдела: «Человеческие ресурсы», manager_id: 101, first_name: 'Сьюзен'}, ------------------------------------ ------------------------------------
операции
MySQL (здесь мы поддерживаем версию 5.6) поддерживает локальные транзакции (в рамках данного сеанса клиента) с помощью таких операторов, как SET autocommit, START TRANSACTION, COMMIT и ROLLBACK. Вот синтаксис START TRANSACTION, COMMIT и ROLLBACK:
НАЧАТЬ СДЕЛКУ транзакция_характеристика [, транзакция_характеристика] ...] transaction_characteristic: С ПОСЛЕДОВАТЕЛЬНЫМ ОСНОВАНИЕМ | ЧИТАЙ ПИШИ | ЧИТАЙТЕ ТОЛЬКО НАЧАЛО [РАБОТАЕТ] COMMIT [РАБОТА] [И [НЕТ] ЦЕПЬ] [[НЕТ] РЕЛИЗ] ROLLBACK [РАБОТА] [И [НЕТ] ЦЕПЬ] [[НЕТ] РЕЛИЗ] SET autocommit = {0 | 1}
В node.js поддержка простых транзакций доступна на уровне соединения:
connection.beginTransaction(function(err) {
if (err) { throw err; }
connection.query('INSERT INTO posts SET title=?', title, function(err, result) {
if (err) {
connection.rollback(function() {
throw err;
});
}
var log ='Post ' + result.insertId + ' added';
connection.query('INSERT INTO log SET data=?', log, function(err, result) {
if (err) {
connection.rollback(function() {
throw err;
});
}
connection.commit(function(err) {
if (err) {
connection.rollback(function() {
throw err;
});
}
console.log('success!');
});
});
});
});
Обратите внимание, что beginTransaction (), commit () и rollback () — это просто вспомогательные функции, которые выполняют команды START TRANSACTION, COMMIT и ROLLBACK соответственно. Важно понимать, что многие команды в MySQL могут вызывать неявную фиксацию, как описано в документации MySQL.
Таймауты
Каждая операция принимает необязательный параметр таймаута бездействия. Это позволяет вам указать соответствующие таймауты для операций. Важно отметить, что эти таймауты являются не частью протокола MySQL, а скорее операциями тайм-аута через клиента. Это означает, что по истечении времени ожидания соединение, на котором оно произошло, будет уничтожено и дальнейшие операции не будут выполнены.
// Kill query after 60s
connection.query({sql: 'SELECT COUNT(*) AS count FROM big_table', timeout: 60000}, function (err, rows) {
if (err && err.code ==='PROTOCOL_SEQUENCE_TIMEOUT') {
throw new Error('too long to count table rows!');
}
if (err) {
throw err;
}
console.log(rows[0].count + ' rows');
});
Структура базы данных «hr»:
Предыдущий: OS Module
Далее: Node-SQLite3
Новый контент: Composer: менеджер зависимостей для PHP , R программирования
script1adsense5code
disqus2code
script1adsense6code
script1adsense7code
script1adsense8code
Last update on August 19 2022 21:50:45 (UTC/GMT +8 hours)
node-mysql: A node.js module implementing the MySQL protocol
This is a node.js driver for mysql. It is written in JavaScript, does not require compiling. It provides all most all connection/query from MySQL. Node-mysql is probably one of the best modules used for working with MySQL database and the module is actively maintained.
We assume that you have already installed MySQL and node.js on Windows or Linux environment.
Here is an example to retrieve the first row from ’employees’ table belongs to ‘hr’ database :
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'datasoft123',
database : 'hr'
});
connection.connect();
connection.query('SELECT * FROM employees', function(err, rows, fields)
{
if (err) throw err;
console.log(rows[0]);
});
connection.end();
Output :
{ EMPLOYEE_ID: 100, FIRST_NAME: 'Steven', LAST_NAME: 'King', EMAIL: '[email protected]', PHONE_NUMBER: '515.123.4567', HIRE_DATE: Wed Jun 17 1987 00:00:00 GMT+0530 (India Standard Time), JOB_ID: 'AD_PRES', SALARY: 24000, COMMISSION_PCT: 0, MANAGER_ID: 0, DEPARTMENT_ID: 90 }
From the above example you can learn how to create a new connection and close the connection.
Contents:
- Install MySQL node.js driver
- Create and terminate connections, connection options
- Error handling
- SSL options
- Pooling connections, options and events
- Escaping query values, identifiers
- Preparing Queries
- Stored procedures
- Joins
- Transactions
- Timeouts
Install MySQL node.js driver
$ npm install mysql
You can install the latest version from Github to check if a bugfix is working. In this case use the following command :
$ npm install felixge/node-mysql
Create connection
Here is the code to establish a connection :
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'example.org',
user : 'root',
password : 'datasoft123'
});
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
Here is an another method to establish a connection by invoking a query :
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'datasoft123'
});
connection.query('SELECT 1', function(err, rows) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected!');
});
Connection Option
Name | Description |
---|---|
host | The hostname of the database. Default is localhost. |
port | The port number to connect to. Default is 3306. |
localAddress | The source IP address to use for TCP connection. (Optional) |
socketPath | The path to a unix domain socket to connect to. When used host and port are ignored. |
user | The MySQL user to authenticate as. |
password | The password of that MySQL user. |
database | Name of the database to use for this connection (Optional). |
charset | The charset for the connection. This is called «collation» in the SQL-level of MySQL (like utf8_general_ci). If a SQL-level charset is specified (like utf8mb4) then the default collation for that charset is used. (Default: ‘UTF8_GENERAL_CI’) |
timezone | The timezone used to store local dates. Default is : ‘local’. |
connectTimeout | The milliseconds before a timeout occurs during the initial connection to the MySQL server. (Default: 10 seconds) |
stringifyObjects | Stringify objects instead of converting to values. See issue #501. (Default: ‘false’) |
insecureAuth | Allow connecting to MySQL instances that ask for the old (insecure) authentication method. (Default: false) |
typeCast | Determines if column values should be converted to native JavaScript types. (Default: true) |
queryFormat | A custom query format function. See Custom format. |
supportBigNumbers | When dealing with big numbers (BIGINT and DECIMAL columns) in the database, you should enable this option (Default: false). |
bigNumberStrings | Enabling both supportBigNumbers and bigNumberStrings forces big numbers (BIGINT and DECIMAL columns) to be always returned as JavaScript String objects (Default: false). Enabling supportBigNumbers but leaving bigNumberStrings disabled will return big numbers as String objects only when they cannot be accurately represented with JavaScript Number objects (which happens when they exceed the [-2^53, +2^53] range), otherwise they will be returned as Number objects. This option is ignored if supportBigNumbers is disabled. |
dateStrings | Force date types (TIMESTAMP, DATETIME, DATE) to be returned as strings rather then inflated into JavaScript Date objects. (Default: false) |
debug | Prints protocol details to stdout. (Default: false) |
trace | Generates stack traces on Error to include call site of library entrance («long stack traces»). Slight performance penalty for most calls. Default is true. |
multipleStatements | Allow multiple mysql statements per query. Be careful with this, it exposes you to SQL injection attacks. (Default: false) |
flags | List of connection flags to use other than the default ones. It is also possible to blacklist default ones. For more information, check Connection Flags. |
ssl | object with ssl parameters or a string containing name of ssl profile. See SSL options. |
Note: The query values are first attempted to be parsed as JSON, and if that fails assumed to be plaintext strings.
Terminating connection
There are two ways to end a connection :
- end() method
- destroy() method
You can terminate a connection by calling the end() method :
connection.end(function(err) {
// The connection is terminated now
});
This will make sure all previously enqueued queries are still before sending a COM_QUIT packet to the MySQL server. If a fatal error occurs before the COM_QUIT packet can be sent, an err argument will be provided to the callback, but the connection will be terminated regardless of that.
destroy() method :
This method terminates a connection immediately. Additionally destroy() guarantees that no more events or callbacks will be triggered for the connection.
connection.destroy();
Unlike end() the destroy() method does not take a callback argument.
Switching users / altering connection state :
MySQL offers a changeUser command that allows you to alter the current user and other aspects of the connection without shutting down the underlying socket:
connection.changeUser({user : 'user2'}, function(err) {
if (err) throw err;
});
The available options:
Name | Description |
---|---|
user | The name of the new user (defaults to the previous one). |
password | The password of the new user (defaults to the previous one). |
charset | The new charset (defaults to the previous one). |
database | The new database (defaults to the previous one). |
A sometimes useful side effect of this functionality is that this function also resets any connection state (variables, transactions, etc.).
Errors encountered during this operation are treated as fatal connection errors by this module.
Error handling
There are several options to handle error within this module :
All errors created by this module are instances of the JavaScript Error object. Additionally they come with two properties:
- err.code :
- A MySQL server error (e.g. ‘ER_ACCESS_DENIED_ERROR’)
- A node.js error (e.g. ‘ECONNREFUSED’)
- An internal error (e.g. ‘PROTOCOL_CONNECTION_LOST’)
- err.fatal : Boolean, indicating if this error is terminal to the connection object.
Fatal errors are propagated (to cause to multiply by any process ) to all pending callbacks. In the example below, a fatal error is triggered by trying to an invalid user name. Therefore in the following example error object is propagated to both pending callbacks :
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'roott',
password : 'datasoft123',
});
connection.connect(function(err) {
console.log(err.code);
console.log(err.fatal);
});
connection.query('SELECT 1', function(err) {
console.log(err.code);
console.log(err.fatal);
});
Output :
ER_ACCESS_DENIED_ERROR true ER_ACCESS_DENIED_ERROR true
In this example, a fatal error is triggered by an invalid user.
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'roott',
password : 'datasoft123'
});
connection.query('SELECT 1', function(err){
if (err){
console.log(err.code);
console.log(err.fatal);
}
});
connection.end();
Output :
E:nodejs>node test.js
ER_ACCESS_DENIED_ERROR
true
Normal errors are delegated only to the callback they belong to. In the following example, only the first callback receives an error (wrong db name), the second query works as expected :
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'datasoft123',
});
//Wrong database name
connection.query('USE kkk', function(err, rows) {
console.log(err.code); // 'ER_BAD_DB_ERROR'
});
connection.query('SELECT 1', function(err, rows) {
// null
console.log(err);
// length of the row 1
console.log(rows.length);
});
Server disconnects :
You may lose the connection to a MySQL server due to network problems, the server timing you out, the server being restarted, or crashing. All of these events are considered fatal errors, and will have the err.code = ‘PROTOCOL_CONNECTION_LOST’. See the Error Handling section for more information.
Re-connecting a connection is done by establishing a new connection. Once terminated, an existing connection object cannot be re-connected by design.
With Pool, disconnected connections will be removed from the pool freeing up space for a new connection to be created on the next getConnection call.
SSL options
The ssl option in the connection options takes a string or an object. When given a string, it uses one of the predefined SSL profiles included. The following profiles are included:
- «Amazon RDS»: this profile is for connecting to an Amazon RDS server and contains the ca from https://rds.amazonaws.com/doc/rds-ssl-ca-cert.pem
When connecting to other servers, you will need to provide an object of options, in the same format as crypto.createCredentials. Please note the arguments expect a string of the certificate, not a file name to the certificate. Here is a simple example:
var connection = mysql.createConnection({
host : 'localhost',
ssl : {
ca : fs.readFileSync(__dirname + '/mysql-ca.crt')
}
});
You can also connect to a MySQL server without properly providing the appropriate CA to trust. You should not do this.
var connection = mysql.createConnection({
host : 'localhost',
ssl : {
// DO NOT DO THIS
// set up your ca correctly to trust the connection
rejectUnauthorized: false
}
});
var connection = mysql.createConnection({
host : 'localhost',
ssl : {
// DO NOT DO THIS
// set up your ca correctly to trust the connection
rejectUnauthorized: false
}
});
Pooling connections
A connection pool is a cache of database connections maintained so that the connections can be reused when future requests to the database are required. Connection pools are used to enhance the performance of executing commands on a database.
Use pool directly.
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'localhost',
user : 'root',
password : 'datasoft123'
});
pool.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
if (err) throw err;
console.log('The solution is: ', rows[0].solution);
});
When you are done with a connection, just call connection.release() and the connection will return to the pool, ready to be used again by someone else.
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'localhost',
user : 'root',
password : 'datasoft123',
database : 'hr'
});
pool.getConnection(function(err, connection) {
// Use the connection
connection.query( 'SELECT * from employees', function(err, rows) {
// And done with the connection.
console.log(rows[0]);
connection.release();
// Don't use the connection here, it has been returned to the pool.
});
});
If you would like to close the connection and remove it from the pool, use connection.destroy() instead. The pool will create a new connection the next time one is needed.
Closing all the connections in a pool
When you are done using the pool, you have to end all the connections or the Node.js event loop will stay active until the connections are closed by the MySQL server. The end method takes an optional callback that you can use to know once all the connections have ended. The connections end gracefully, so all pending queries will still complete and the time to end the pool will vary. Once pool.end() has been called, pool.getConnection and other operations can no longer be performed
Pool options
Pool supports all the options of normal connection. In addition here are some extra options :
Name | Description |
---|---|
acquireTimeout | The milliseconds before a timeout occurs during the connection acquisition. This is slightly different from connectTimeout, because acquiring a pool connection does not always involve making a connection. (Default: 10 seconds) |
waitForConnections | Determines the pool’s action when no connections are available and the limit has been reached. If true, the pool will queue the connection request and call it when one becomes available. If false, the pool will immediately call back with an error. (Default: true) |
connectionLimit | The maximum number of connections to create at once. (Default: 10) |
queueLimit | The maximum number of connection requests the pool will queue before returning an error from getConnection. If set to 0, there is no limit to the number of queued connection requests. (Default: 0) |
Pool events
connection :
The pool will emit a connection event when a new connection is made within the pool. If you need to set session variables on the connection before it gets used, you can listen to the connection event.
pool.on('connection', function (connection) {
connection.query('SET SESSION auto_increment_increment=1')
});
enqueue :
The pool will emit an enqueue event when a callback has been queued to wait for an available connection.
pool.on('enqueue', function () {
console.log('Waiting for available connection slot');
});
Escaping query values
SQL injection is a technique (like other web attack mechanisms) to attack data driven applications. This attack can bypass a firewall and can affect a fully patched system. The attacker takes the advantage of poorly filtered or not correctly escaped characters embedded in SQL statements into parsing variable data from user input. The attacker inject arbitrary data, most often a database query, into a string that’s eventually executed by the database through a web application (e.g. a login form).
To avoid SQL Injection attacks, you should always escape any user provided data before using it inside a SQL query. You can do so using the connection.escape() or pool.escape() methods :
var userId = 'some user provided value'; var sql = 'SELECT * FROM users WHERE id = ' + connection.escape(userId); connection.query(sql, function(err, results) { // ... });
Alternatively, you can use ? characters as placeholders for values you would like to have escaped like this:
connection.query('SELECT * FROM users WHERE id = ?', [userId], function(err, results) { // ... });
Different value types are escaped differently, here is how:
- Numbers are left untouched
- Booleans are converted to true / false strings
- Date objects are converted to ‘YYYY-mm-dd HH:ii:ss’ strings
- Buffers are converted to hex strings, e.g. X’0fa5′
- Strings are safely escaped
- Arrays are turned into list, e.g. [‘a’, ‘b’] turns into ‘a’, ‘b’
- Nested arrays are turned into grouped lists (for bulk inserts), e.g. [[‘a’, ‘b’], [‘c’, ‘d’]] turns into (‘a’, ‘b’), (‘c’, ‘d’)
- Objects are turned into key = ‘val’ pairs. Nested objects are cast to strings.
- undefined / null are converted to NULL
- NaN / Infinity are left as-is. MySQL does not support these, and trying to insert them as values will trigger MySQL errors until they implement support.
Here is an example on INSERT INTO statement :
var post = {id: 1, title: 'Hello MySQL'}; var query = connection.query('INSERT INTO posts SET ?', post, function(err, result) { // Neat! }); console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
You can also use the escaping function directly, see the following example :
var query = "SELECT * FROM posts WHERE title=" + mysql.escape("Hello MySQL"); console.log(query); // SELECT * FROM posts WHERE title='Hello MySQL'
Escaping query identifiers
As SQL identifier (database / table / column name) is provided by a user, you should escape it with mysql.escapeId(identifier), connection.escapeId(identifier) or pool.escapeId(identifier) like this :
var sorter = 'date'; var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter); connection.query(sql, function(err, results) { // ... });
It also supports adding qualified identifiers. It will escape both parts.
var sorter = 'date'; var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId('posts.' + sorter); connection.query(sql, function(err, results) { // ... });
Alternatively, you can use ?? characters as placeholders for identifiers you would like to have escaped like this:
var userId = 1; var columns = ['username', 'email']; var query = connection.query('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId], function(err, results) { // ... }); console.log(query.sql); // SELECT `username`, `email` FROM `users` WHERE id = 1
Note : The last character sequence is experimental and syntax might change.
When you pass an Object to .escape() or .query(), .escapeId() is used to avoid SQL injection in object keys.
Preparing Queries
MySQL 5.6 provides support for server-side prepared statements. This support takes advantage of the efficient client/server binary protocol available since MySQL 4.1. You can use mysql.format to prepare a query with multiple insertion points, utilizing the proper escaping for ids and values. A simple example of this follows:
var sql = "SELECT * FROM ?? WHERE ?? = ?"; var inserts = ['users', 'id', userId]; sql = mysql.format(sql, inserts);
Following this you then have a valid, escaped query that you can then send to the database safely. This is useful if you are looking to prepare the query before actually sending it to the database. As mysql.format is exposed from SqlString.format you also have the option (but are not required) to pass in stringifyObject and timezone, allowing you provide a custom means of turning objects into strings, as well as a location-specific/timezone-aware Date.
Custom format :
If you prefer to have another type of query escape format, there’s a connection configuration option you can use to define a custom format function. You can access the connection object if you want to use the built-in .escape() or any other connection function.
Here’s an example of how to implement another format:
connection.config.queryFormat = function (query, values) { if (!values) return query; return query.replace(/:(w+)/g, function (txt, key) { if (values.hasOwnProperty(key)) { return this.escape(values[key]); } return txt; }.bind(this)); }; connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });
Getting the id of an inserted row :
If you are inserting a row into a table with an auto increment primary key, you can retrieve the insert id like this:
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function(err, result) { if (err) throw err; console.log(result.insertId); });
When dealing with big numbers (above JavaScript Number precision limit), you should consider enabling support BigNumbers option to be able to read the insert id as a string, otherwise it will throw.
This option is also required when fetching big numbers from the database, otherwise you will get values rounded to hundreds or thousands due to the precision limit.
Getting the number of affected rows.
You can get the number of affected rows from an insert, update or delete statement.
«changedRows» differs from «affectedRows» in that it does not count updated rows whose values were not changed.
connection.query('DELETE FROM posts WHERE title = "wrong"', function (err, result) { if (err) throw err; console.log('deleted ' + result.affectedRows + ' rows'); })
Getting the connection ID
You can get the MySQL connection ID («thread ID») of a given connection using the threadId property.
connection.connect(function(err) { if (err) throw err; console.log('connected as id ' + connection.threadId); });
Executing queries in parallel :
The MySQL protocol is sequential, this means that you need multiple connections to execute queries in parallel. You can use a Pool to manage connections, one simple approach is to create one connection per incoming http request.
Streaming query rows
Sometimes you may want to select large quantities of rows and process each of them as they are received. This can be done like this:
var query = connection.query('SELECT * FROM posts'); query .on('error', function(err) { // Handle error, an 'end' event will be emitted after this as well }) .on('fields', function(fields) { // the field packets for the rows to follow }) .on('result', function(row) { // Pausing the connnection is useful if your processing involves I/O connection.pause(); processRow(row, function() { connection.resume(); }); }) .on('end', function() { // all rows have been received });
Please note a few things about the example above:
- Usually you will want to receive a certain amount of rows before starting to throttle the connection using pause(). This number will depend on the amount and size of your rows.
- pause() / resume() operate on the underlying socket and parser. You are guaranteed that no more ‘result’ events will fire after calling pause().
- You MUST NOT provide a callback to the query() method when streaming rows.
- The ‘result’ event will fire for both rows as well as OK packets confirming the success of a INSERT/UPDATE query.
Additionally you may be interested to know that it is currently not possible to stream individual row columns, they will always be buffered up entirely. If you have a good use case for streaming large fields to and from MySQL, I’d love to get your thoughts and contributions on this.
Multiple statement queries :
Support for multiple statements is disabled for security reasons (it allows for SQL injection attacks if values are not properly escaped). To use this feature you have to enable it for your connection:
var connection = mysql.createConnection({multipleStatements: true});
Once enabled, you can execute multiple statement queries like any other query:
connection.query('SELECT 1; SELECT 2', function(err, results) { if (err) throw err; // `results` is an array with one element for every statement in the query: console.log(results[0]); // [{1: 1}] console.log(results[1]); // [{2: 2}] });
Additionally you can also stream the results of multiple statement queries:
var query = connection.query('SELECT 1; SELECT 2'); query .on('fields', function(fields, index) { // the fields for the result rows that follow }) .on('result', function(row, index) { // index refers to the statement this result belongs to (starts at 0) });
If one of the statements in your query causes an error, the resulting Error object contains a err.index property which tells you which statement caused it. MySQL will also stop executing any remaining statements when an error occurs.
Please note that the interface for streaming multiple statement queries is experimental and I am looking forward to feedback on it.
Stored procedures
You can call stored procedures from your queries as with any other mysql driver. Here is the original procedure code :
DELIMITER $$ CREATE PROCEDURE my_procedure_User_Variables() BEGIN SET @x = 15; SET @y = 10; SELECT @x, @y, @[email protected]; END$$
Output when it was executed in MySQL :
mysql> CALL my_procedure_User_Variables() ; +------+------+-------+ | @x | @y | @[email protected] | +------+------+-------+ | 15 | 10 | 5 | +------+------+-------+ 1 row in set (0.04 sec) Query OK, 0 rows affected (0.05 sec)
Now call the stored procedure from node.js :
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : 'datasoft123', database : 'hr' }); connection.connect(); connection.query("CALL my_procedure_User_Variables();", function(err, rows) { if (err) throw err; console.log(rows); }); connection.end();
Output :
[ [ { '@x': 15, '@y': 10, '@[email protected]': 5 } ], { fieldCount: 0, affectedRows: 0, insertId: 0, serverStatus: 2, warningCount: 0, message: '', protocol41: true, changedRows: 0 } ]
Joins
You can call JOINS from your queries as with any other mysql driver. Here is an example :
Write a query to display the department ID, department name and manager first name. See ‘hr’ database.
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : 'datasoft123', database : 'hr' }); connection.connect(); connection.query("SELECT d.department_id, d.department_name, e.manager_id, e.first_name FROM departments d INNER JOIN employees e ON (d.manager_id = e.employee_id);", function(err, rows) { if (err) throw err; console.log(rows); }); connection.end();
Output :
[ { department_id: 10, department_name: 'Administration', manager_id: 101, first_name: 'Jennifer' }, { department_id: 20, department_name: 'Marketing', manager_id: 100, first_name: 'Michael' }, { department_id: 30, department_name: 'Purchasing', manager_id: 100, first_name: 'Den' }, { department_id: 40, department_name: 'Human Resources', manager_id: 101, first_name: 'Susan' }, ------------------------------------ ------------------------------------
Transactions
MySQL (here we maintain version 5.6) supports local transactions (within a given client session) through statements such as SET autocommit, START TRANSACTION, COMMIT, and ROLLBACK. Here is the syntax of START TRANSACTION, COMMIT, and ROLLBACK :
START TRANSACTION transaction_characteristic [, transaction_characteristic] ...] transaction_characteristic: WITH CONSISTENT SNAPSHOT | READ WRITE | READ ONLY BEGIN [WORK] COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE] ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE] SET autocommit = {0 | 1}
In node.js simple transaction support is available at the connection level :
connection.beginTransaction(function(err) {
if (err) { throw err; }
connection.query('INSERT INTO posts SET title=?', title, function(err, result) {
if (err) {
connection.rollback(function() {
throw err;
});
}
var log = 'Post ' + result.insertId + ' added';
connection.query('INSERT INTO log SET data=?', log, function(err, result) {
if (err) {
connection.rollback(function() {
throw err;
});
}
connection.commit(function(err) {
if (err) {
connection.rollback(function() {
throw err;
});
}
console.log('success!');
});
});
});
});
Please note that beginTransaction(), commit() and rollback() are simply convenience functions that execute the START TRANSACTION, COMMIT, and ROLLBACK commands respectively. It is important to understand that many commands in MySQL can cause an implicit commit, as described in the MySQL documentation
Timeouts
Every operation takes an optional inactivity timeout option. This allows you to specify appropriate timeouts for operations. It is important to note that these timeouts are not part of the MySQL protocol, and rather timeout operations through the client. This means that when a timeout is reached, the connection it occurred on will be destroyed and no further operations can be performed.
// Kill query after 60s
connection.query({sql: 'SELECT COUNT(*) AS count FROM big_table', timeout: 60000}, function (err, rows) {
if (err && err.code === 'PROTOCOL_SEQUENCE_TIMEOUT') {
throw new Error('too long to count table rows!');
}
if (err) {
throw err;
}
console.log(rows[0].count + ' rows');
});
Structure of ‘hr’ database :
Previous:
OS Module
Next:
Node-SQLite3
Доброго времени суток!
Express.js 4
Скажите пожалуйста как обработать ошибку MySQL запроса?
Javascript | ||
|
Javascript | ||
|
Если я ввожу правильный Логин и пароль то сервер работает и меня переводит на window.location.href=»/home»;
Но если я ввел не верный логин то валит ошибку!
ошибка в cmd:
PowerShell | ||
|
как же обработать ошибку?
C:UsersDimaDesktopMySERVER20161MySERVER_24112 016node_modulesmysqllibprotocolParser.js:78
throw err; // Rethrow non-MySQL errors
^
TypeError: Cannot read property ‘DB_USER’ of
undefined
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
Node.Js поддерживает работу со всеми популярными системами управления базами данных. Microsoft SQL Server не исключение.
В репозитории npm существует целый ряд пакетов, которые позволяют работать с этой СУБД. Однако все их можно условно разделить на две большие группы в зависимости от реализуемого подхода.
-
Непосредственная работа с базой данных c использованием SQL запросов;
-
Сопоставление объектной модели и структуры базы данных посредство ORM.
В данной статье речь пойдёт о первом подходе.
Установка клиента для SQL Server
Для того чтобы выполнить запрос к базе данных SQL Server в Node.js существует целый ряд библиотек. Мы воспользуемся библиотекой @frangiskos/mssql, которая основана на node-mssql и предоставляет достаточно простой интерфейс для работы.
Библиотека имеет открытый исходный код, который доступен на GitHub (https://github.com/frangiskos/mssql).
Установить её можно при помощи npm следующей командой:
npm install @frangiskos/mssql |
Подключение к базе данных
Чтобы подключиться к базе данных необходимо подключить библиотеку к проекту и создать объект SqlConfig, в котором описаны параметры подключения.
Ниже приведён пример указанных операций:
import { SqlConfig, sql } from ‘@frangiskos/mssql’; const sqlConfig: SqlConfig = { user: ‘userName’, password: ‘pass’, server: ‘host\SQLS_Instance’, database: ‘TestDb’ }; |
Далее нужно передать объект SqlConfig в метод init объекта sql.
Библиотека @frangiskos/mssql работает с SQL Server по протоколу TCP. Поэтому предварительно убедитесь, что для экземпляра SQL Server, к которому вы планируете подключиться включен протокол TCP и открыты соответствующие порты.
Если подключение завершено успешно, можно выполнять запросы к базе данных при помощи метода query, но о нём позже.
Так как метод init ничего не возвращает, обработать ошибку подключения можно только при помощи блока try-catch.
try { sql.init(sqlConfig); } catch (error) { console.error(error); } |
Запрос на выборку
Запрос на выборку данных выполняется при помощи метода query/ Этот метод обычно принимает как минимум один параметр – строку с текстом запроса. Остальное — параметры запроса (о них мы поговорим позже).
Ниже показан пример, получения всех записей из таблицы:
sql.query(‘SELECT * FROM TestTable’).then(data => console.log(data)).catch(error => console.error(error)); |
Метод query возвращает Promise. Поэтому данные мы можем получить только в методе then или при помощи async/await.
try { const data = await sql.query(‘SELECT * FROM TestTable’).; } catch (error) { console.error(error); } |
Записи из таблицы возвращаются в виде JSON массива, где каждый элемент представляет собой JSON объект с полями соответствующими структуре таблицы.
Например, для таблицы, которая включает поля id (целое число) и testValue (nvarchar), массив с результатами будет выглядеть приблизительно так:
[{ id: 1, testValue: ‘Test 1’ }, { id: 2, testValue: ‘Test 2’ }, { id: 3, testValue: ‘Test 3’ }, { id: 4, testValue: ‘Test 4’ }, { id: 5, testValue: ‘Test 5’ }] |
Запрос без выборки данных
Если запрос не предполагает получения данных из базы (UPDATE, INSERT, CREATE и т. д.), он выполняется аналогичным образом. Единственное отличие состоит только в том, что в этом случае нет необходимости обрабатывать возвращаемые данные в приложении. Поэтому, метод then можно использовать только для контроля успешного выполнения запроса.
Ниже показан пример запроса на выполнение хранимой процедуры:
let testValue = ‘Test 5’; sql.query(`EXEC AddTestValue @testValue=N‘${testValue}’`).then(() => { console.log(‘Success!’) }).catch(error => console.error(error)); |
Как мы видим при помощи библиотеки @frangiskos/mssql можно спокойно работать с SQL Server используя синтаксис Transact-SQL.
В приведённом примере есть один очень серьёзный подвох.
Значение входного параметра хранимой процедуры передаётся непосредственно в строке запроса, что чревато далеко идущими последствиями. Поэтому настоятельно рекомендуется в подобных случаях применять запросы с параметрами (параметрические запросы), речь о которых пойдёт ниже.
Параметрический запрос
Библиотека @frangiskos/mssql поддерживает параметрические запросы.
Для этой цели предусмотрен специальный синтаксис.
Параметры в тексте запроса обозначаются как @P и далее номер параметра (обязательно), начиная с 1.
Обратите внимание, что подобные имена параметров являются заерезервированными.
Значения параметров запроса передаются как параметры метода query (начиная со второго параметра, первый всегда строка запроса).
Далее представлен предыдущий пример, который был изменён для использования параметрического запроса.
sql.query(`EXEC AddTestValue @testValue=@P1`,testValue).catch(error => console.error(error)); |
Метод query, ранее принимавший только один параметр, теперь принимает два. Строку запроса и значение параметра.
Количество используемых параметров не ограничено.
Сопоставление параметров запроса их значениям осуществляется слева направо. То есть, второй параметр метода query — @P1, третий — @P2, четвёртый — @P3 и т. д.
Например, такой запрос к рассмотренной ранее тестовой таблице вернёт не все пять значений, а только два.
sql.query(‘SELECT * FROM TestTable WHERE id >= @P1 AND id < @P2’,2,4).then(data => console.log(data)).catch(error => console.error(error)); |
Результат будет уже таким:
[{ id: 2, testValue: ‘Test 2’ }, { id: 3, testValue: ‘Test 3’ }] |
Специализированные методы
В принципе, изложенное выше, это всё, что необходимо знать для успешной работы с SQL Server в Node.js при помощи @frangiskos/mssql. Но, возможности библиотеки этим не ограничиваются.
Есть ещё два метода, которые вызываются аналогично query, но предназначены для частных случаев и потому используются значительно реже. Однако эти методы могут существенно упростить вам работу.
Первый из них queryOne — полный аналог query, но возвращает только первую из выбранных записей. Этот метод избавляет от необходимости использовать «TOP 1» в SQL запросах.
Второй insertReturnIdentity, предназначен для выполнения вставки данных в таблицу с возвратом идентификатора добавленной записи в случае успеха. Этот метод возвращает Promise. Поэтому, значение идентификатора доступно только в методе then или с использованием async/await.
sql.insertReturnIdentity(‘INSERT INTO TestTable VALUES (‘Test6′)’).then(id => console.log(id)).catch(error => console.error(error)); |
Но, даже несмотря на это роль метода insertReturnIdentity переоценить сложно, так как благодаря ему полностью отпадает потребность поиска только, что добавленной записи.
Также стоит обратить внимание на методы q, q1 и ii.
Эти методы по сути являются псевдонимами для query, queryOne и insertReturnIdentity соответственно. Они позволяют сократить объём кода за счёт краткости. Но, стоит ли приносить качество кода в жертву подобной «оптимизации» уже решать вам.
На этом, мы завершаем рассмотрение библиотеки @frangiskos/mssql.
Конечно данная библиотека не поражает разнообразием классов и методов, но за то она содержит лишь то, что действительно необходимо для работы и предоставляет к этому удобный доступ, что нередко гораздо ценнее.
08-03-2018
19,118,
3,359
Join Date: Sep 2000
Last Activity: 15 July 2022, 8:51 AM EDT
Location: Asia Pacific, Cyberspace, in the Dark Dystopia
Posts: 19,118
Thanks Given: 2,351
Thanked 3,359 Times in 1,878 Posts
Node.js and mysql — ER_ACCESS_DENIED_ERROR
This problem has been killing me all day, and I cannot solve it.
Basically, I am using node.js with the mysql module and it will not connect to the database.
Here is the JS code snippet in node.js:
Code:
app.get("/test", function(req, res) { var mysql = require("mysql"); var con = mysql.createConnection({ host: "127.0.0.1", user: "node", password: "myPassword", database: "myDatabase", port: 3306 }); console.log("Connection Object Created"); con.connect(function(error1) { if (error1) { console.log(error1); return; } else { console.log("Connected1"); } }); });
I have checked the grants and permissions and all is just fine in MySQL and I can easily connect to the DB manually from the command line using:
Code:
mysql -u node -p myDatabase
After hours and hours of this, it always give error:
Code:
Connection Object Created { Error: ER_ACCESS_DENIED_ERROR: Access denied for user 'node'@'127.0.0.1' (using password: YES) at Handshake.Sequence._packetToError (/var/node/node_modules/mysql/lib/protocol/sequences/Sequence.js:47:14) at Handshake.ErrorPacket (/var/node/node_modules/mysql/lib/protocol/sequences/Handshake.js:124:18) at Protocol._parsePacket (/var/node/node_modules/mysql/lib/protocol/Protocol.js:278:23) at Parser.write (/var/node/node_modules/mysql/lib/protocol/Parser.js:76:12) at Protocol.write (/var/node/node_modules/mysql/lib/protocol/Protocol.js:38:16) at Socket.<anonymous> (/var/node/node_modules/mysql/lib/Connection.js:91:28) at Socket.<anonymous> (/var/node/node_modules/mysql/lib/Connection.js:502:10) at Socket.emit (events.js:182:13) at addChunk (_stream_readable.js:283:12) at readableAddChunk (_stream_readable.js:264:11) -------------------- at Protocol._enqueue (/var/node/node_modules/mysql/lib/protocol/Protocol.js:144:48) at Protocol.handshake (/var/node/node_modules/mysql/lib/protocol/Protocol.js:51:23) at Connection.connect (/var/node/node_modules/mysql/lib/Connection.js:118:18) at /var/node/index.js:27:5 at Layer.handle [as handle_request] (/var/node/node_modules/express/lib/router/layer.js:95:5) at next (/var/node/node_modules/express/lib/router/route.js:137:13) at Route.dispatch (/var/node/node_modules/express/lib/router/route.js:112:3) at Layer.handle [as handle_request] (/var/node/node_modules/express/lib/router/layer.js:95:5) at /var/node/node_modules/express/lib/router/index.js:281:22 at Function.process_params (/var/node/node_modules/express/lib/router/index.js:335:12) code: 'ER_ACCESS_DENIED_ERROR', errno: 1045, sqlMessage: 'Access denied for user 'node'@'127.0.0.1' (using password: YES)', sqlState: '28000', fatal: true }
I have Googled and read at least 30 tutorials, watched at least 5 YT videos on node.js and MySQL, and read the docs many time.
I cannot get past this error.
Darn!
Does anyone here use node.js and MySQL ??? If so, please help.
Code:
package.json ... "dependencies": { "express": "^4.16.3", "mysql": "^2.16.0", "nodemon": "^1.18.3" },
Code:
me@myServer:~# mysql -u node -p myDatabase Enter password: Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Welcome to the MySQL monitor. Commands end with ; or g. .... mysql> show grants; +----------------------------------------------------------------------------------------------------------------------+ | Grants for node@localhost | +----------------------------------------------------------------------------------------------------------------------+ | GRANT ALL PRIVILEGES ON *.* TO 'node'@'localhost' IDENTIFIED BY PASSWORD '*7F8BC63ED005891Axxxxxxxx0FBB5A48CB5FFB9' | +----------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql>