NodeJS Mysql Stop Server Crash on Error - mysql

I am using https://github.com/felixge/node-mysql
and everytime a mysql query throw an error, for example if a row does not exist. The node server crashes.
connection.connect();
connection.query('SELECT * from table1 where id = 2', function(err, rows, fields) {
if (err) console.log(err);
if (rows[0]) {
console.log('The result is ', rows[0].user);
}
});
connection.end();
How do I simply print the errors to the page rather than crash the server.

If an error occurs, your code console.log's it but tries to access rows[0] anyway. In case of errors rows will be undefined so rows[0] will trigger a new error.
Easily fixed with an else in combination with a length check:
if (err) {
console.log(err);
} else if (rows.length) {
console.log('The result is ', rows[0].user);
} else {
console.log("Query didn't return any results.");
}

I prefer to use the return statement:
connection.connect();
connection.query('SELECT * from table1 where id = 2', function(err, rows, fields) {
if (err) return console.log(err);
if (rows[0]) {
console.log('The result is ', rows[0].user);
}
});
connection.end();
This is cleaner IMO and guarantees that I wont leave anything out of an if statement block where it shouldn't.

Related

Sending MySQL Queries in bulk to save memory

I'm currently trying to insert multiple rows per second into my SQL database. While doing this im coming across that the program is consuming upwards of 1GB ram steadily increasing. The program then crashes due to running out of memory.
I have tried sending the queries in bulk by stringing them together and then running. My current solution does work, however, I'm 90% sure it is the cause of the memory consumption
function insertUsername(id, username, discrim, unix) {
vars = [id, username, discrim, unix];
conn.query("SELECT username, discrim FROM usernames WHERE discordID = ? LIMIT 1", id, function (err, results) {
if (err) throw err;
if (!results[0] == null) {
if (results[0].username != username || results[0].discrim != discrim) {
conn.query(insertUsernameSQL, vars, function (err) {
if (err) throw err;
});
}
}
return;
});
conn.query(insertUsernameSQL, vars, function (err) {
if (err) throw err;
});
}
function insertMessage(unix, id, username, discrim, message, server, sid) {
vars = [unix, id, username, discrim, message, sid, server];
conn.query(insertMessageSQL, vars, function (err) {
if (err) throw err;
});
}
My attempt at a bulk sender:
function transaction_bldr(vars){
sql_transaction.push(vars);
console.log(sql_transaction.length);
if (sql_transaction.length > 1){
conn.query(sql, [sql_transaction], function(err) {
if (err) throw err;
console.log(1);
});
sql_transaction = [];
}
}
After using the first two functions I get this: https://cdn.discordapp.com/attachments/619654531596288000/619963742339203122/unknown.png

MySQL isolation levels in nodejs. Is each query in connection isolated or each pool isolated?

My current isolation level for MySQL is tx_transaction = REPEATABLE-READ for each session.
So when I run the below code in different terminals the transactions are serially executed, meaning before the commit of the first transaction, the second would not start.
START TRANSACTION;
SELECT *
FROM test
WHERE id = 4 FOR UPDATE;
UPDATE test
SET parent = 98
WHERE id = 4;
So if I implement this in nodeJS, which of the following would give same result as running two terminals?
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'me',
password : 'secret',
database : 'my_db'
});
connection.connect();
let query =
START TRANSACTION;
SELECT *
FROM test
WHERE id = 4 FOR UPDATE;
UPDATE test
SET parent = 98
WHERE id = 4;
connection.query(query, function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
connection.query(query, function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
connection.end();
or using pools
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'example.org',
user : 'bob',
password : 'secret',
database : 'my_db'
});
let query =
START TRANSACTION;
SELECT *
FROM test
WHERE id = 4 FOR UPDATE;
UPDATE test
SET parent = 98
WHERE id = 4;
pool.query(query, function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
connection.release();
});
pool.query(query, function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
connection.release();
});
My first guess was that the pools would create separate connections and sending queries in same connection would be same as typing in queries in the same terminal. However the documentation says https://github.com/mysqljs/mysql#pooling-connections under introduction section that
Every method you invoke on a connection is queued and executed in
sequence.
and I am not exactly sure what that means.
Also, if I use connection pooling, can I be 100% sure that the concurrently running queries are handled by different sessions? So for example if the pool is not released in the first query, would the second query ALWAYS be executed by another session?
I have done a few tests and realized that Connection Pooling results to the expected outcome.
when I do the following with just connection
let pool = mysql.createConnection({
connectionLimit:10,
host: 'localhost',
user: 'root',
password: 'thflqkek12!',
database: 'donationether'
});
connection.beginTransaction(function (err) {
console.log('first transaction has started');
if (err) {
console.log(err);
return;
}
connection.query(`INSERT INTO users VALUES (null, 0, 'username', 'token')`, function (err, results, fields) {
if (err) {
console.log(err);
return;
}
setTimeout(function () {
connection.commit(function (err) {
if (err) {
console.log(err);
return;
}
console.log('first query done');
connection.release();
})
}, 2000)
});
});
connection.beginTransaction(function (err) {
console.log('second transaction has started');
if(err) {
console.log(err);
return;
}
connection.query(`UPDATE users SET username = 'c_username' WHERE username = 'username'`,function (err, results, fields) {
if(err) {
console.log(err);
return;
}
connection.commit(function (err) {
if(err) {
console.log(err);
return;
}
console.log('second query done');
connection.release();
})
});
});
It leads to following output
first transaction has started
second transaction has started
second query done
first query done
Meaning that the transaction opened by the first connection is ignored and the second transaction finishes before. However, when I use connection pooling for following code,
let pool = mysql.createPool({
connectionLimit:10,
host: 'localhost',
user: 'root',
password: 'thflqkek12!',
database: 'donationether'
});
pool.getConnection(function (err, connection) {
connection.beginTransaction(function (err) {
console.log('first transaction has started');
if (err) {
console.log(err);
return;
}
connection.query(`INSERT INTO users VALUES (null, 0, 'username', 'token')`, function (err, results, fields) {
console.log('first query has started');
if (err) {
console.log(err);
return;
}
setTimeout(function () {
connection.commit(function (err) {
if (err) {
console.log(err);
return;
}
console.log('first query done');
connection.release();
});
}, 2000)
});
});
});
pool.getConnection(function (err, connection) {
connection.beginTransaction(function (err) {
console.log('second transaction has started');
if(err) {
console.log(err);
return;
}
connection.query(`UPDATE users SET username = 'c_username' WHERE username = 'username'`,function (err, results, fields) {
console.log('second query has started');
if(err) {
console.log(err);
return;
}
connection.commit(function (err) {
if(err) {
console.log(err);
return;
}
console.log('second query done');
connection.release();
})
});
});
});
The output is as following
first transaction has started
second transaction has started
first query has started
//2seconds delay
second query has started
first query done
second query done
meaning that the first transaction is blocking the second transaction from executing.
So when the documentation said
Every method you invoke on a connection is queued and executed in sequence
It meant that they are delivered to the database in sequence but it will still be asynchronous and parallel even under transaction. However, connection pooling leads to instantiation of multiple connections and transaction within different pool connection behaves as expected for each transaction.

Query not working using node.js node-mysql

Whats wrong with my query? im having this error:
con.query(
'SELECT nick FROM channels WHERE room=1room',
function(err, rows) {
if (err) throw err;
console.log(rows);
}
);
I tried this, and i have the same error:
var room = "1room";
con.query(
'SELECT nick FROM channels WHERE room=' + room,
function(err, rows) {
if (err) throw err;
console.log(rows);
}
);
It is treating 1room as a variable, not a string. Wrap it in quotes and it should work.
con.query(
'SELECT nick FROM channels WHERE room="1room"',
function(err, rows) {
if (err) throw err;
console.log(rows);
}
);
For your second example, you should get in the habit of escaping the variables you use in queries for security reasons (to prevent SQL injection).
var room = "1room";
con.query(
'SELECT nick FROM channels WHERE room=?',
[room],
function(err, rows) {
if (err) throw err;
console.log(rows);
}
);

nodejs + mysql: how can i reopen mysql after end()?

code as follows:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
port :"3306",
database :"mydb",
user : 'root',
password : '007007',
});
var isCon = true;
connection.connect(
function (err) {
console.log(isCon);
if (err) {
isCon=false;
console.error("error connecting :"+err);
return;
};
}
);
if(isCon){
connection.query('select * from tb_items', function(err, result) {
if (err) throw err;
console.log('The solution is: ', result);
console.log('The typeof solution is ',typeof(result));
debugger;
});
connection.end();
}
connection.connect(
function (err) {
console.log(isCon);
if (err) {
isCon=false;
console.error("error connecting :"+err);
return;
};
}
);
if(isCon){
connection.query('select * from tb_items', function(err, result) {
if (err) throw err;
console.log('The solution is: ', result);
console.log('The typeof solution is ',typeof(result));
debugger;
});
connection.end();
}
i just open()-->connect()-->query()-->end(),then did it again,but second time , there is a error : Error:Could not enqueue Handshake after invoking quiting .
question : maybe i can't reopen it after end().but i just wanna kwon ,if i end(),how can i reopen it?
no, you can't, just create another one. All state in the connection class only relevant for current connection, so having "reopenWithSameConfig" method is possible, but you should really do this from outside.
Also, you don't need to close connection on each query - just continue to reuse it without calling .end()
If you want multiple connections and automatic disposal of dead connections you should use Pool class.
One more note: your isCon check is incorrect, connection.query is called before connect() callback so it's always true. It's safe to just check error in query callback itself. If connection was not successful error is propagated to a queued command

Use node-mysql to execute additional queries from each result

I'm trying to get a node-mysql connection query to work in series with the result of the original query. After all the setup is done, this is the problematic part. It seems that the connection has already ended. How can I ensure that the query in processRow gets executed in tandem with the result of the original?
function processRow(row, callback){
connection.query('INSERT INTO other_table VALUES (?)', row.id, function(err, rows, fields) {
if (err) throw err;
});
callback();
}
var query = connection.query('SELECT id from tbl limit 2');
query
.on('error', function(err){
throw err;
})
.on('fields', function(fields){
})
.on('result', function(row){
processRow(row, function(){
connection.resume();
});
})
.on('end', function(){
//
});
connection.end();
https://github.com/felixge/node-mysql
function processRow(row, callback){
connection.query('INSERT INTO other_table VALUES (?)', row.id, function(err, rows, fields) {
if (err) throw err;
callback();//callback should go here
});
}
then you could end the connection:
query.on('result', function(row){
processRow(row, function(){
connection.end(); //maybe end the connection once insertion into the table is done
});
})
I think the issue with your code that you have to call connection.pause() before calling processRow()