zoukankan      html  css  js  c++  java
  • Node.jsでMySQLを使うメモ

    インストール

    npm install mysql

    コネクション

    var mysql      = require('mysql');
    var connection = mysql.createConnection({
      host     : 'localhost',
      user     : 'me',
      password : 'secret'
    });
    
    //これは省略してもoK。
    connection.connect();
    

    コネクションでもエラー処理とかしたいならこんな感じ

    connection.connect(function(err) {
      if (err) {
        console.error('error connecting: ' + err.stack);
        return;
      }
    
      console.log('connected as id ' + connection.threadId);
    });
    

    クエリ 其の壱

    connection.query('SELECT * FROM `books` WHERE `author` = "David"', function (error, results, fields) {
    
    })
    

    resultは結果。fieldsは各フィールドの詳細。
    filedsの中身はこんな感じ

    [{"catalog":"def","db":"hoge","table":"books","orgTable":"books","name":"ID","orgName":"ID","charsetNr":63,"length":11,"type":3,"flags":16899,"decimals":0,"zeroFill":false,"protocol41":true},・・・・
    

    クエリ 其の弐 プレースホルダーを使ったクエリ

    connection.query('SELECT * FROM `books` WHERE `author` = ?', ['David'], function (error, results, fields) {
    });
    
    //insert
    connection.query("insert into posts ?",{title:'post'},function
    (error,results,fields){
    });
    
    
    //複数カラムがあっても1つの?でOKなinsertの書き方
    connection.query("insert into posts set ?",{title:'post',content:'content'},function
    (error,results,fields){
    });
    
    //複数行insertするなら
    connection.query('insert into hoge(NAME) values(?),(?),(?)',['fuga','fuga','fuga'],function(error,results,fields){
    });
    

    第一引数のSQL文中にクエスチョンマークを指定。
    第二引数に配列を指定してあげると、?に入る。
    この時第二引数で渡した値はエスケープされる。
    第一引数で渡した文字列はエスケープされないので値はプレースホルダで渡すほうがよさそう

    もし自前でエスケープするなら、下記が使える
    mysql.escape()connection.escape() または pool.escape()

    クエリ 其の参 オプションで指定

    connection.query({
      sql: 'SELECT * FROM `books` WHERE `author` = ?',
      timeout: 40000, // 40s
      values: ['David']
    }, function (error, results, fields) {
    });
    

    jQueryの$.ajaxみたいなもんですね。
    こっちのほうが見た目がすっきりしてます。

    クエリ 其の四 フィールド名にもプレイスホルダーを使う

    フィールド名に使う場合、??を使います

    var userId = 1;
    var columns = ['username', 'email'];
    var query = connection.query('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId], function(err, results) {
      // ...
    });
    

    これをSQL文で書くとこうなる

    SELECT username,email FROM users WHERE id = 1;
    

    クエリ 其の五 プリペアリングクエリ?

    プリペアードステートメントみたいな感じですかね?

    var sql = "SELECT * FROM ?? WHERE ?? = ?";
    var inserts = ['users', 'id', userId];
    sql = mysql.format(sql, inserts);
    

    これもすっきり書けていいですね。

    クエリ 其の六 カスタムフォーマット

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

    うまく説明できないですが、上のコードの通りです。

    挿入したレコードのIDを取得する

    connection.query('INSERT INTO posts SET ?', {title: 'test'}, function(err, result) {
      if (err) throw err;
    
      console.log(result.insertId);
    });
    

    複数挿入した場合は一番最後のIDが返ります。

    挿入、更新、削除したレコード数を取得する

    connection.query('DELETE FROM posts WHERE title = "wrong"', function (err, result) {
      if (err) throw err;
    
      console.log('deleted ' + result.affectedRows + ' rows');
    })
    

    こっちはUpdateの際に使う

    connection.query('UPDATE posts SET ...', function (err, result) {
      if (err) throw err;
    
      console.log('changed ' + result.changedRows + ' rows');
    })
    

    affectedRowsとの違いは、changedRowsは変更がなかった行は含まれない点
    affectedRows ・・・Updateの対象になったレコード数
    cahngedRows ・・・実際に値が更新されたレコード数
    つまりはこういうことです

    こんなテーブルがあったとして
    table test
    ID NAME
    1  HOGE
    2  FUGA
    3  HOGE
    4  FUGA
    
    これを実行すると
    update test set NAME = 'FUGA';
    
    affectedRows = 4
    changedRows = 2
    
    となります。
    

    Streaming query rows

    なんて訳せばよいの?
    こんな書き方もできます。

    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
        //pause()を実行すると、以降resultイベントが発生しない
        connection.pause();
    
    
        processRow(row, function() {
          connection.resume();
        });
      })
      .on('end', function() {
        // all rows have been received
      });
    

    複数の命令文を実行する場合

    //コネクション作る際にmultipleStatementsにtrueをセット
    var connection = mysql.createConnection({multipleStatements: true});
    
    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}]
    });
    

    このようにresultsが配列で返ってくる
    Streamで書くなら

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

    ストアドプロシージャ。

     connection.query('call hoge()');
    

    ここでも?が使えるのかな?試してない。

    重複したフィールド名の解決

    よくわからんけど、フィールド名が重複するような場合には、nestTablesを有効にしておくと、
    テーブル名でネストして結果を返してくれるよ

    var options = {sql: '...', nestTables: true};
    connection.query(options, function(err, results) {
      /* results will be an array like this now:
      [{
        table1: {
          fieldA: '...',
          fieldB: '...',
        },
        table2: {
          fieldA: '...',
          fieldB: '...',
        },
      }, ...]
      */
    });
    

    またはフィールド名にテーブル名をつけてマージすることもできるよ

    var options = {sql: '...', nestTables: '_'};
    connection.query(options, function(err, results) {
      /* results will be an array like this now:
      [{
        table1_fieldA: '...',
        table1_fieldB: '...',
        table2_fieldA: '...',
        table2_fieldB: '...',
      }, ...]
      */
    });
    

    トランザクション

    コネクションレベルで使えます

    //トランザクション開始
    connection.beginTransaction(function(err) {
      if (err) { throw err; }
      connection.query('INSERT INTO posts SET title=?', title, function(err, result) {
        if (err) { 
          //insertに失敗したら戻す
          connection.rollback(function() {
            throw err;
          });
        }
    
        var log = 'Post ' + result.insertId + ' added';
    
        connection.query('INSERT INTO log SET data=?', log, function(err, result) {
          if (err) { 
            //insertに失敗したら戻す
            connection.rollback(function() {
              throw err;
            });
          }  
          //コミットする
          connection.commit(function(err) {
            if (err) { 
              connection.rollback(function() {
                throw err;
              });
            }
            console.log('success!');
          });
        });
      });
    });
    

    コネクションプール(Pooling connections)

    var mysql = require('mysql');
    var pool  = mysql.createPool({
      connectionLimit : 10,
      host            : 'example.org',
      user            : 'bob',
      password        : 'secret'
    });
    
    
    pool.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
      if (err) throw err;
    
      console.log('The solution is: ', rows[0].solution);
    });
    

    シングルコネクションの場合

    var mysql = require('mysql');
    var pool  = mysql.createPool({
      host            : 'example.org',
      user            : 'bob',
      password        : 'secret'
    });
    

    使っちゃってもリリースしてあげればプールに戻るよ

    var mysql = require('mysql');
    var pool  = mysql.createPool(...);
    
    pool.getConnection(function(err, connection) {
      // Use the connection
      connection.query( 'SELECT something FROM sometable', function(err, rows) {
        // プールに戻す
        connection.release();
    
        // ここでconnectionをつかっちゃだめだよ。すでにプールに返しちゃったからね。
      });
    });
    

    もう使わないならdestroy

    connection.destroy()

    プールイベント

    connection

    コネクションが使われたゾ

    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');
    });
    //endしたあとにpool.getConnectionとかしても、もう何もしてやんないから。
    

    プールを閉園します。

    pool.end(function (err) {
      // all connections in the pool have ended
    });
    

    プールクラスター(PoolCluster)

    プール(各コネクション)に名前を付けてあげましょうってことかな?

    // create
    var poolCluster = mysql.createPoolCluster();
    
    // add configurations
    poolCluster.add(config); // anonymous group
    poolCluster.add('MASTER', masterConfig);
    poolCluster.add('SLAVE1', slave1Config);
    poolCluster.add('SLAVE2', slave2Config);
    
    // remove configurations
    poolCluster.remove('SLAVE2'); // By nodeId
    poolCluster.remove('SLAVE*'); // By target group : SLAVE1-2
    
    // Target Group : ALL(anonymous, MASTER, SLAVE1-2), Selector : round-robin(default)
    poolCluster.getConnection(function (err, connection) {});
    
    // Target Group : MASTER, Selector : round-robin
    poolCluster.getConnection('MASTER', function (err, connection) {});
    
    // Target Group : SLAVE1-2, Selector : order
    // If can't connect to SLAVE1, return SLAVE2. (remove SLAVE1 in the cluster)
    poolCluster.on('remove', function (nodeId) {
      console.log('REMOVED NODE : ' + nodeId); // nodeId = SLAVE1 
    });
    
    poolCluster.getConnection('SLAVE*', 'ORDER', function (err, connection) {});
    
    // of namespace : of(pattern, selector)
    poolCluster.of('*').getConnection(function (err, connection) {});
    
    var pool = poolCluster.of('SLAVE*', 'RANDOM');
    pool.getConnection(function (err, connection) {});
    pool.getConnection(function (err, connection) {});
    
    // close all connections
    poolCluster.end(function (err) {
      // all connections in the pool cluster have ended
    });
    

    Ping

    connection.ping(function (err) {
      if (err) throw err;
      console.log('Server responded to ping');
    })
    

    タイムアウト処理

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

    エラー処理

    err.codeには下記の種類があります。
    MySQL serverのエラー (たとえば 'ER_ACCESS_DENIED_ERROR')
    node.jsのエラー (たとえば 'ECONNREFUSED')
    内部エラー (たとえば 'PROTOCOL_CONNECTION_LOST')

    var connection = require('mysql').createConnection({
      port: 84943, // わざと間違ったポートを指定してみる
    });
    
    connection.connect(function(err) {
      console.log(err.code); // 'ECONNREFUSED'
      console.log(err.fatal); // true
    });
    
    connection.query('SELECT 1', function(err) {
      console.log(err.code); // 'ECONNREFUSED'
      console.log(err.fatal); // true
    });
    

    エラーはほかの処理には影響しない(含まれない)。
    たとえば下記のような場合

    //存在しないDBに接続
    connection.query('USE name_of_db_that_does_not_exist', function(err, rows) {
      console.log(err.code); // 'ER_BAD_DB_ERRORが発生'
    });
    //その後下記クエリを実行
    connection.query('SELECT 1', function(err, rows) {
      console.log(err); // null ここにエラーは含まれない
      console.log(rows.length); // 1
    });
    

    こんな風にエラー処理することもできます。

    connection.on('error', function(err) {
      console.log(err.code); // 'ER_BAD_DB_ERROR'
    });
    
    connection.query('USE name_of_db_that_does_not_exist');
    

    型変換(Type casting)

    デフォルトで、JavaScriptの型に下記のように自動変換されます。
    (一部未翻訳スミマセン)

    Number型

    TINYINT
    SMALLINT
    INT
    MEDIUMINT
    YEAR
    FLOAT
    DOUBLE

    Date型

    TIMESTAMP
    DATE
    DATETIME

    Buffer型

    TINYBLOB
    MEDIUMBLOB
    LONGBLOB
    BLOB
    BINARY
    VARBINARY
    BIT (last byte will be filled with 0 bits as necessary)

    String型

    Note text in the binary character set is returned as Buffer, rather than a string.

    CHAR
    VARCHAR
    TINYTEXT
    MEDIUMTEXT
    LONGTEXT
    TEXT
    ENUM
    SET
    DECIMAL (may exceed float precision)
    BIGINT (may exceed float precision)
    TIME (could be mapped to Date, but what date would be set?)
    GEOMETRY (never used those, get in touch if you do)
    It is not recommended (and may go away / change in the future) to disable type casting, but you can currently do so on either the connection:

    おすすめしないけど、型変換をoffにできます。

    //コネクションレベルでoff
    var connection = require('mysql').createConnection({typeCast: false});
    
    //クエリレベルでoff
    var options = {sql: '...', typeCast: false};
    var query = connection.query(options, function(err, results) {
    
    });
    

    また、自分で型変換を定義できます。

    connection.query({
      sql: '...',
      typeCast: function (field, next) {
        if (field.type == 'TINY' && field.length == 1) {
          return (field.string() == '1'); // 1 = true, 0 = false
        }
        return next();
      }
    });
    

    参考リンク

    https://github.com/felixge/node-mysql

    終わり

  • 相关阅读:
    Microsoft .NET Framework 2.0实现发送邮件(Email)总结
    Microsoft .NET Framework 2.0对文件传输协议(FTP)操作(上传,下载,新建,删除,FTP间传送文件等)实现汇总
    抽象类
    WingIDE 单步调试 Uliweb Python 代码
    Android 4.0 SDK的离线方式安装
    .NET 3.5 中WCF客户端代理性能改进以及最佳实践
    在linux上部署Redmine
    认识jQuery mobile 框架,资源,书籍
    如何使用搜索技巧来成为一名高效的程序员
    Management Console 工具管理类软件通用开发框架(开放源码)
  • 原文地址:https://www.cnblogs.com/c-x-a/p/5462037.html
Copyright © 2011-2022 走看看