mysql Node.js Driver

repository·master·Indexed 12 days ago

https://github.com/mysqljs/mysql

A pure JavaScript Node.js driver for MySQL (version 2.18.1). It provides a way to establish connections via options or URL strings, supports connection pooling with mysql.createPool(), and offers advanced multi-host management through PoolCluster. The driver is 100% MIT licensed and requires no compilation.

Tokens
16.7K
Snippets
60
Records
66
Agent score
95%

What's inside mysql

  1. Manage multiple hosts with PoolCluster

    master

    A PoolCluster allows you to manage multiple connection pools across different hosts, supporting grouping, retries, and selection strategies (e.g., for Master/Slave setups).

    Adding and Removing Nodes

    Nodes can be added with an automatic name or a specific identifier. They can be removed by ID or by a pattern (using wildcards).

    Selecting Nodes

    You can retrieve connections from specific groups, using patterns (wildcards or Regular Expressions), or using the of() method to create a sub-pool with a specific selector.

    PoolCluster Options

    • canRetry: If true, attempts to reconnect when a connection fails. (Default: true)
    • removeNodeErrorCount: Number of failures allowed before a node is removed from the cluster. (Default: 5)
    • restoreNodeTimeout: Milliseconds to wait before attempting to reconnect to a failed node. If 0, the node is removed and never re-used. (Default: 0)
    • defaultSelector: The strategy used to pick a node. Options: RR (Round-Robin), RANDOM, or ORDER (first available).
    var poolCluster = mysql.createPoolCluster();
    
    // Add nodes
    poolCluster.add('MASTER', masterConfig);
    poolCluster.add('SLAVE1', slave1Config);
    poolCluster.add('SLAVE2', slave2Config);
    
    // Get connection from a specific group (Selector: Round-Robin)
    poolCluster.getConnection('SLAVE*', function (err, connection) {});
    
    // Get connection using a pattern and specific selector
    poolCluster.getConnection(/^SLAVE[12]$/, 'ORDER', function (err, connection) {});
    
    // Create a sub-pool with a specific selector
    var pool = poolCluster.of('SLAVE*', 'RANDOM');
    pool.query('SELECT 1');
    
    // Close the cluster
    poolCluster.end(function (err) {});
  2. Escape query values to prevent SQL Injection

    master

    To prevent SQL Injection, always escape user-provided data. This library performs client-side escaping.

    Methods for escaping:

    • connection.escape(value)
    • pool.escape(value)
    • mysql.escape(value)
    • Using ? placeholders in .query() (recommended).

    Escaping behavior by type:

    • Numbers: Left untouched.
    • Booleans: Converted to true / false.
    • Dates: Converted to 'YYYY-mm-dd HH:ii:ss' strings.
    • Buffers: Converted to hex strings (e.g., X'0fa5').
    • Strings: Safely escaped.
    • Arrays: Converted to lists (e.g., ['a', 'b'] $\rightarrow$ 'a', 'b').
    • Nested Arrays: Converted to grouped lists for bulk inserts (e.g., [['a', 'b'], ['c', 'd']] $\rightarrow$ ('a', 'b'), ('c', 'd')).
    • Objects: Converted to key = 'val' pairs for each enumerable property. If a property is a function, it is skipped; if it is an object, toString() is used.
    • undefined / null: Converted to NULL.
    • NaN / Infinity: Left as-is (Note: MySQL does not support these and may throw errors).

    Special Object Handling:

    • Objects with a .toSqlString() method will use that method's return value as the raw SQL.
    • mysql.raw(string) creates an object that bypasses all escaping, useful for dynamic SQL functions like CURRENT_TIMESTAMP().
    // Using placeholders (Best Practice)
    connection.query('SELECT * FROM users WHERE id = ?', [userId], function (error, results, fields) {
      // ...
    });
    
    // Using mysql.raw for SQL functions
    var CURRENT_TIMESTAMP = mysql.raw('CURRENT_TIMESTAMP()');
    connection.query('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42], function (error, results) {
      // ...
    });
    
    // Bulk insert using nested arrays
    connection.query('INSERT INTO table (col1, col2) VALUES ?', [['val1', 'val2'], ['val3', 'val4']], function (error, results) {
      // ...
    });
  3. Handle errors in mysqljs/mysql

    master

    The module uses standard JavaScript Error objects with additional properties to provide context about MySQL or Node.js errors.

    Error Properties

    • err.code: String. Contains the MySQL server error symbol (e.g., 'ER_ACCESS_DENIED_ERROR'), a Node.js error code (e.g., 'ECONNREFUSED'), or an internal error code (e.g., 'PROTOCOL_CONNECTION_LOST').
    • err.errno: Number. The MySQL server error number (only for MySQL server errors).
    • err.fatal: Boolean. Indicates if the error is terminal to the connection object. This is not defined for non-protocol errors.
    • err.sql: String. The full SQL of the failed query.
    • err.sqlState: String. The five-character SQLSTATE value (only for MySQL server errors).
    • err.sqlMessage: String. A textual description of the error (only for MySQL server errors).

    Error Propagation Behavior

    • Fatal Errors: Propagated to all pending callbacks. If no callbacks are pending, the error is emitted as an 'error' event on the connection object.
    • Normal Errors: Only delegated to the specific callback belonging to the failed operation.
    • Unhandled Errors: If a normal error occurs with no callback, or a fatal error occurs with no listeners, it is emitted as an 'error' event. In Node.js, unhandled 'error' events will print a stack trace and kill the process. Always provide a callback or an 'error' listener to prevent silent failures or process crashes.
    var connection = require('mysql').createConnection({
      port: 1 // example blocked port
    });
    
    connection.connect(function(err) {
      console.log(err.code); // 'ECONNREFUSED'
      console.log(err.fatal); // true
    });
    
    connection.query('SELECT 1', function (error, results, fields) {
      console.log(error.code); // 'ECONNREFUSED'
      console.log(error.fatal); // true
    });
  4. Quickstart: Establish a connection and run a query

    master

    To use mysql, require the module, create a connection object with your database credentials, and call .connect(). You can then execute queries using .query().

    Note that every method invoked on a connection is queued and executed in sequence. To close a connection gracefully, use .end(), which ensures all remaining queries are executed before sending a quit packet to the server.

    var mysql      = require('mysql');
    var connection = mysql.createConnection({
      host     : 'localhost',
      user     : 'me',
      password : 'secret',
      database : 'my_db'
    });
    
    connection.connect();
    
    connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
      if (error) throw error;
      console.log('The solution is: ', results[0].solution);
    });
    
    connection.end();
  5. Stream query rows using events

    master

    To process large quantities of rows without buffering them all into memory, use the event-based streaming approach.

    Important requirements:

    • You MUST NOT provide a callback to the query() method when streaming.
    • The 'result' event fires for both data rows and OK packets (for INSERT/UPDATE).
    • Use connection.pause() and connection.resume() to throttle processing if your row handling involves I/O. This prevents the internal buffer from overflowing.
    • Be careful not to leave the connection paused for too long, or you may encounter Error: Connection lost: The server closed the connection. due to the MySQL net_write_timeout setting.

    Available events:

    • 'error': Emitted on error. An 'end' event will follow.
    • 'fields': Emitted with the field packets for the upcoming rows.
    • 'result': Emitted for each row (or OK packet).
    • 'end': Emitted when all rows have been received.
    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 connection is useful if your processing involves I/O
        connection.pause();
    
        processRow(row, function() {
          connection.resume();
        });
      })
      .on('end', function() {
        // all rows have been received
      });
  6. Gracefully close a Pool with pool.end()

    master

    To prevent the Node.js event loop from staying active, you must call pool.end() when you are finished with the pool (e.g., during a server shutdown).

    Important:

    • Once pool.end() is called, no new operations like pool.getConnection can be performed.
    • Wait until all connections are released (or pool.query calls complete) before calling end().
    • pool.end() will call connection.end() on all active connections, queuing a QUIT packet.
    pool.end(function (err) {
      // all connections in the pool have ended
    });
  7. Enable debug mode for connection troubleshooting

    master

    To debug connection issues, you can enable debug mode. This prints all incoming and outgoing packets to stdout.

    Enable all packets:

    var connection = mysql.createConnection({debug: true});

    Restrict to specific packet types: Pass an array of packet types to the debug option to limit output (e.g., to just queries and data packets).

    var connection = mysql.createConnection({debug: ['ComQueryPacket', 'RowDataPacket']});
  8. Use connection pooling with mysql.createPool()

    master

    Instead of managing individual connections, use mysql.createPool(config) to manage a cache of connections. This improves performance and simplifies connection management.

    Shortcut Method

    Use pool.query() for single, one-off queries. This automatically handles acquiring and releasing a connection from the pool.

    Manual Connection Management

    If you need to share connection state (like session variables or transactions) across multiple queries, use pool.getConnection(). You must call connection.release() when finished to return the connection to the pool. If you want to permanently remove a connection from the pool, use connection.destroy() instead.

    var mysql = require('mysql');
    var pool  = mysql.createPool({
      connectionLimit : 10,
      host            : 'example.org',
      user            : 'bob',
      password        : 'secret',
      database        : 'my_db'
    });
    
    // Shortcut: automatically acquires and releases
    pool.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
      if (error) throw error;
      console.log('The solution is: ', results[0].solution);
    });
    
    // Manual: useful for sharing state
    pool.getConnection(function(err, connection) {
      if (err) throw err;
    
      connection.query('SELECT something FROM sometable', function (error, results, fields) {
        // Release the connection back to the pool
        connection.release();
    
        if (error) throw error;
      });
    });
  9. Establish connections explicitly or implicitly

    master

    You can establish a connection in two ways:

    Explicit Connection

    Use connection.connect(callback) to handle connection errors (such as handshake or network issues) via a callback. This is the recommended approach.

    var mysql      = require('mysql');
    var connection = mysql.createConnection({
      host     : 'example.org',
      user     : 'bob',
      password : 'secret'
    });
    
    connection.connect(function(err) {
      if (err) {
        console.error('error connecting: ' + err.stack);
        return;
      }
    
      console.log('connected as id ' + connection.threadId);
    });

    Implicit Connection

    Invoking a query via connection.query() will implicitly establish the connection if it is not already connected.

    var mysql      = require('mysql');
    var connection = mysql.createConnection(...);
    
    connection.query('SELECT 1', function (error, results, fields) {
      if (error) throw error;
      // connected!
    });

    Warning: Any connection error (handshake or network) is considered a fatal error.

  10. Install the mysql module

    master

    Install the mysql driver via npm. Node.js 0.6 or higher is required.

    To install the stable version:

    $ npm install mysql

    To install the latest version directly from GitHub (useful for testing bugfixes):

    $ npm install mysqljs/mysql
  11. Run unit and integration tests

    master

    The test suite is divided into unit tests and integration tests.

    Running Unit Tests

    Unit tests can be run on any machine without a MySQL server:

    $ FILTER=unit npm test

    Running Integration Tests

    Integration tests require a running MySQL server. You must provide connection details via environment variables:

    • MYSQL_DATABASE
    • MYSQL_HOST or MYSQL_SOCKET
    • MYSQL_PORT
    • MYSQL_USER
    • MYSQL_PASSWORD

    Example execution:

    $ mysql -u root -e "CREATE DATABASE IF NOT EXISTS node_mysql_test"
    $ MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_DATABASE=node_mysql_test MYSQL_USER=root MYSQL_PASSWORD= FILTER=integration npm test
  12. Enable and use multiple statement queries

    master

    By default, multiple statements are disabled for security. To enable them, set multipleStatements: true in your connection configuration.

    Standard Querying: When executing multiple statements, results is an array where each element corresponds to a statement in the query.

    Streaming Multiple Statements: When streaming, the 'fields' and 'result' events provide an index argument (starting at 0) indicating which statement the data belongs to. If a statement causes an error, the error object will contain an err.index property. Note that MySQL stops executing remaining statements if one fails.

    // Enable the feature
    var connection = mysql.createConnection({multipleStatements: true});
    
    // Execute multiple statements
    connection.query('SELECT 1; SELECT 2', function (error, results, fields) {
      if (error) throw error;
      console.log(results[0]); // [{1: 1}]
      console.log(results[1]); // [{2: 2}]
    });
    
    // Stream multiple statements
    var query = connection.query('SELECT 1; SELECT 2');
    query
      .on('fields', function(fields, index) {
        // index refers to the statement index
      })
      .on('result', function(row, index) {
        // index refers to the statement index
      });