Showing posts with label node-mysql. Show all posts
Showing posts with label node-mysql. Show all posts

Wednesday, August 8, 2018

Error: Handshake inactivity timeout in Node.js MYSQL module

Leave a Comment

I'm using node-mysql and most of the queries. Working. some queries not working. I tried every version of Node (from 0.5...) until (5.6.0), I also tried (4.0) and (4.1), Nothing helps.

I tried to change maually, and didn't work. I tried to change the sequence file to: this._idleTimeout = -1; and didn't help.

I read the issues and GitHub, and nothing helped.

I can try to fix it by myself, but I need more information. Where is the timeout, why? when? what is this type of message? Where is the timeout came from?

MYSQL_ERROR     { [Error: Handshake inactivity timeout]   code: 'PROTOCOL_SEQUENCE_TIMEOUT',   fatal: true,    timeout: 10000 }   

1 Answers

Answers 1

Ok, the timeout comes from the Protocol.js file line:162. If you checkout node-mysql you'll see that it is a variable "timeout" for queries. If you set the timeout to something a lot higher than 10000, the default, then the error should go away. An example is

pool = require('mysql').createPool({     connectionLimit : 1000,     connectTimeout  : 60 * 60 * 1000,     aquireTimeout   : 60 * 60 * 1000,     timeout         : 60 * 60 * 1000,     host            : process.env.DB_HOST,     user            : process.env.DB_USERNAME,     password        : process.env.DB_PASSWORD,     database        : process.env.DB_DATABASE }); 

You can also edit the timeout in the Sequence.js file (node_modules/mysql/lib/protocol/sequence/Sequence.js)

this._timeout = 100000;

Read More

Wednesday, August 16, 2017

Node Mysql On Duplicate Key Update only updates unique row

Leave a Comment

I am using MySQL 5.7 with Node JS 6.11.0 and am trying to update a UNIQUE MySQL column whenever I insert a conflicting row. However, when I try inserting a conflicting record, only the existing record is updated to NULL and no insert happens. Here is my code

     pool.getConnection(function(err, connection) {         var newClass = req.body;         var query = `INSERT INTO classes SET ? ON DUPLICATE KEY UPDATE teacher_id = NULL`;          connection.query(query, newClass, function(err, result) {                console.log(result);             if(result.affectedRows >= 1) {                 res.status(201).end();                 res.json(result);             }         });         connection.release();     });` 

I have to run the query twice for the row to be inserted; the first time the conflicting column is set to null then when I run the same query again, the row is inserted since there are no conflicts.

I have taken the SQL generated and directly run it from MySql console and I still have to run the query twice for the new row to be inserted. I do not understand why it is behaving this way.

Sql statement is

INSERT INTO classes SET `stream` = 'Red', `form` = '1', `teacher_id` = '7' ON DUPLICATE KEY UPDATE teacher_id = NULL 

My create table SQL is

| classes | CREATE TABLE `classes` (       `id` int(11) NOT NULL AUTO_INCREMENT,       `form` varchar(10) NOT NULL,       `stream` varchar(15) NOT NULL,       `teacher_id` int(11) DEFAULT NULL,       PRIMARY KEY (`id`),       UNIQUE KEY `teacher_id` (`teacher_id`),       CONSTRAINT `classes_ibfk_1` FOREIGN KEY (`teacher_id`) REFERENCES `teachers`        ( `id` )     ) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=latin1 |` 

Why is MySQL behaving this way?

2 Answers

Answers 1

INSERT INTO classes         SET stream = 'Red', form = '1',teacher_id = '7'     ON DUPLICATE KEY UPDATE teacher_id = NULL; 

Is telling MySQL when there is a conflicting record (duplicate unique or primary key), to set the offending row's teacher_id column to null and stop.

You have a couple options to achieve your desired result.

First you can use the REPLACE syntax.

REPLACE INTO classes SET stream = 'Red', form = '1', teacher_id = '7'; 

Which will first delete the offending row with the UNIQUE or Primary Key constraint, and Insert a new row with the specified values. The drawback is any omitted column values would be lost and set to their default values. A new auto-generated (if any) id will also be created if not specified in the query. If there is no offending record a normal INSERT will occur.

Otherwise, you can utilize VALUES within the UPDATE clause.

INSERT INTO classes         SET stream = 'Red', form = '1', teacher_id = '7'     ON DUPLICATE KEY UPDATE stream = VALUES(stream),                             form   = VALUES(form); 

This will instead, update the records of the offending row to the values specified in the INSERT portion of the query.

References:


Updated based on new intentions

In order to create a new record while leaving the previous row, you would need to first invalidate the UNIQUE constraint on the existing row, prior to using INSERT. There is currently no method to do this with MySQL in a single query.

Due to limitations on INSERT, the easiest way to accomplish what you need is to run an UPDATE query prior to the INSERT query.

UPDATE classes     SET teacher_id = NULL    WHERE teacher_id = '7'; INSERT INTO classes    SET stream = 'Red',     form = '1',    teacher_id = '7'; 

This will first check for a conflicting teacher_id record and set it to null. If no conflicting record exists, no update will occur. The following INSERT would then create the desired record, without a conflict occurring.

Answers 2

If you want to insert data based on condition try this

INSERT INTO table1 SELECT 'Red',1,7 FROM table2 where teacher_id IS NULL; 

else if you want to update based on trying this.

update table1 SET stream = 'Red', form = '1', teacher_id = '7' where teacher_id IS NULL; 

Note: NULL = NULL is not really FALSE - it's NULL again. But it's not TRUE either, so IF(NULL = NULL) won't execute For example, NULL will test FALSE even against NULL itself. So, working with NULL is only done with the aforementioned functions (and IS NULL()). Your query could be rewritten as above.

Read More

Wednesday, April 27, 2016

Use promise to process MySQL return value in node.js

Leave a Comment

I have a python background and is currently migrating to node.js. I have problem adjusting to node.js due to its asynchronous nature.

For example, I am trying to return a value from a MySQL function.

function getLastRecord(name) {     var connection = getMySQL_connection();      var query_str =     "SELECT name, " +     "FROM records " +        "WHERE (name = ?) " +     "LIMIT 1 ";      var query_var = [name];      var query = connection.query(query_str, query_var, function (err, rows, fields) {         //if (err) throw err;         if (err) {             //throw err;             console.log(err);             logger.info(err);         }         else {             //console.log(rows);             return rows;         }     }); //var query = connection.query(query_str, function (err, rows, fields) { }  var rows = getLastRecord('name_record');  console.log(rows); 

After some reading up, I realize the above code cannot work and I need to return a promise due to node.js's asynchronous nature. I cannot write node.js code like python. How do I convert getLastRecord() to return a promise and how do I handle the returned value?

In fact, what I want to do is something like this;

if (getLastRecord() > 20> {     console.log("action"); } 

How can this be done in node.js in a readable way?

I would like to see how promises can be implemented in this case using bluebird.

5 Answers

Answers 1

This is gonna be a little scattered, forgive me.

First, assuming this code uses the mysql driver API correctly, here's one way you could wrap it to work with a native promise:

function getLastRecord(name) {     return new Promise(function(resolve, reject) {         // If you use bluebird, it comes with a Promise.try helper         // for avoiding this. The *point* of this try is to make         // sure that all errors get handled by the promise chain.         // Functions using nodebacks have a concept of "unchecked"         // errors that get thrown rather than passed to the callback         // but this is considered Bad Form in promise-land         try {             var connection = getMySQL_connection();              var query_str =             "SELECT name, " +             "FROM records " +                "WHERE (name = ?) " +             "LIMIT 1 ";              var query_var = [name];              connection.query(query_str, query_var, function (err, rows, fields) {                 // Call reject on error states,                 // call resolve with results                 if (err) {                     return reject(err);                 }                 resolve(rows);             });         } catch (err) {             reject(err);         }     }); }  getLastRecord('name_record').then(function(rows) {     // now you have your rows, you can see if there are <20 of them }).catch((err) => setImmediate(() => { throw err; })); // Throw async to escape the promise chain 

So one thing: You still have callbacks. Callbacks are just functions that you hand to something to call at some point in the future with arguments of its choosing. So the function arguments in xs.map(fn), the (err, result) functions seen in node and the promise result and error handlers are all callbacks. This is somewhat confused by people referring to a specific kind of callback as "callbacks," the ones of (err, result) used in node core in what's called "continuation-passing style", sometimes called "nodebacks" by people that don't really like them.

For now, at least (async/await is coming eventually), you're pretty much stuck with callbacks, regardless of whether you adopt promises or not.

Also, I'll note that promises aren't immediately, obviously helpful here, as you still have a callback. Promises only really shine when you combine them with Promise.all and promise accumulators a la Array.prototype.reduce. But they do shine sometimes, and they are worth learning.

Answers 2

You don't need to use promises, you can use a callback function, something like that:

function getLastRecord(name, next) {     var connection = getMySQL_connection();      var query_str =     "SELECT name, " +     "FROM records " +         "LIMIT 1 ";      var query_var = [name];      var query = connection.query(query_str, query_var, function (err, rows, fields) {         //if (err) throw err;         if (err) {             //throw err;             console.log(err);             logger.info(err);             next(err);         }         else {             //console.log(rows);             next(null, rows);         }     }); //var query = connection.query(query_str, function (err, rows, fields) { }  getLastRecord('name_record', function(err, data) {    if(err) {       // handle the error    } else {       // handle your data     } }); 

Answers 3

I have modified your code to use Q(NPM module) promises. I Assumed your 'getLastRecord()' function that you specified in above snippet works correctly.

You can refer following link to get hold of Q module

Click here : Q documentation

var q = require('q');  function getLastRecord(name) {  var deferred = q.defer(); // Use Q  var connection = getMySQL_connection();  var query_str = "SELECT name, " + "FROM records " +    "WHERE (name = ?) " + "LIMIT 1 ";  var query_var = [name];  var query = connection.query(query_str, query_var, function (err, rows, fields) {     //if (err) throw err;     if (err) {         //throw err;                    deferred.reject(err);     }     else {         //console.log(rows);                    deferred.resolve(rows);     } }); //var query = connection.query(query_str, function (err, rows, fields) {  return deferred.promise; }    // Call the method like this getLastRecord('name_record')  .then(function(rows){    // This function get called, when success    console.log(rows);   },function(error){    // This function get called, when error    console.log(error);   }); 

Answers 4

To answer your initial question: How can this be done in node.js in a readable way?

There is a library called co, which gives you the possibility to write async code in a synchronous workflow. Just have a look and npm install co.

The problem you face very often with that approach, is, that you do not get Promise back from all the libraries you like to use. So you have either wrap it yourself (see answer from @Joshua Holbrook) or look for a wrapper (for example: npm install mysql-promise)

(Btw: its on the roadmap for ES7 to have native support for this type of workflow with the keywords async await, but its not yet in node: node feature list.)

Answers 5

This can be achieved quite simply, for example with bluebird, as you asked:

var Promise = require('bluebird');  function getLastRecord(name) {     return new Promise(function(resolve, reject){         var connection = getMySQL_connection();          var query_str =             "SELECT name, " +             "FROM records " +             "WHERE (name = ?) " +             "LIMIT 1 ";          var query_var = [name];          var query = connection.query(query_str, query_var, function (err, rows, fields) {             //if (err) throw err;             if (err) {                 //throw err;                 console.log(err);                 logger.info(err);                 reject(err);             }             else {                 resolve(rows);                 //console.log(rows);             }         }); //var query = connection.query(query_str, function (err, rows, fields) {     }); }   getLastRecord('name_record')     .then(function(rows){         if (rows > 20) {             console.log("action");         }     })     .error(function(e){console.log("Error handler " + e)})     .catch(function(e){console.log("Catch handler " + e)}); 
Read More