Two *identical* SQL statements behaving differently in PhpMyAdmin vs NodeJS - mysql

I'm trying to get the smallest ID (by world) that is not used via this SQL query:
"SELECT MAX(`objects`.`id`) as nextID FROM `objects` WHERE `objects`.`world`='1'"
NodeJS:
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit: 10,
host: '********',
user: '*********',
password: '*******',
database: databaseName
});
function getNextObjectID(worldID, cb) {
var q = "SELECT MAX(`objects`.`id`) as nextID FROM `objects` WHERE `objects`.`world`='"+worldID+"'";
console.log(q);
pool.query(q, function(err, results, fields) {
console.log(err);
console.log(results);
console.log(fields);
});
}
Previously, I had a more in depth approach that included ids used previously, but it also was having this issue so I've reverted down to this simpler method.
I run this through node and phpmyadmin. When node is doing it, it automatically inserts the world id (and yes I print out the actual query and get that it is identical upon execution). When phpmyadmin executes it returns 14. When node executes its rarely 14 and most of the time null. I have no idea why it would change. All other queries behave normally.

There was an asynchronous delete being called by someone else, it was reading next id before a large amount of rows got inserted.

Related

Use 1 single MySQL connection to provide result to multiple Users

I have used one signle connection object of MYSQL in node JS to serve for multiple users.
I mean to say that MySQL connection will be created upon starting the script & it will remain same until the life of the node script/server.
Practically, this is possible to do & i have done the same. Please take a look at below code of NodeJS/MySQL script.
#################################
var http = require('http');
var mysql = require('mysql');
var con = mysql.createConnection({
host: "192.168.1.105",
user: "root",
password: "XXXXXX",
database: "mydb"
});
con.connect(function(err) {
if (err) {
console.error('error: ' + err.message);
process.exit(1);
}
http.createServer(function (req, res) {
continueExecution(req,res);
}).listen(8082);
});
async function continueExecution(req,res){
res.write('calledddd\n');
for (let step = 0; step < 50; step++) {
// Runs 5 times, with values of step 0 through 4.
var bar = `Company Inc ${step}`;
var sql = `INSERT INTO customers (name, address) VALUES ('${bar}', 'Highway 37')`;
res.write(sql + "\n");
con.query(sql, function (err, result) {
if (err) throw err;
res.write("1 record inserted\n");
});
}
res.write('reached\n');
for (let ste = 0; ste < 50; ste++) {
res.write('started Update\n');
var bar = `Company Inc ${ste}`;
var sql = `UPDATE customers SET name = 'UPDATE RECORD' WHERE name = '${bar}'`;
con.query(sql, function (err, result) {
if (err) throw err;
res.write(result.affectedRows + " record(s) updated\n");
if(ste == 50) {
res.writeHead(200, {'Content-Type': 'text/html\n'});
res.write('Databse connected\n');
res.end();
}
});
}
}
#################################
I have several questions in my mind as i am technical expert. But i didn't find any resources over my questions. Please help me on this
Q1. Are there any type of consequences of using one single MySQL connection to provide response to multiple users?
Q2. Let's take an example.
100 users wants to access table name "users_data" at the same time. 25 users are updating their records on the same table with unique primary key. 50 users are selecting their records. another 25 users deleting their records.
All these operations are being done at the same time via parallel Node Script calls from remote device.
To complete all these MySQL transactions, system is using only 1 database connection.
What will happen in this case?
To answer your questions, one of the consequences of using a unique connection is that it can lead to slower request execution.
In fact, even if node will make the requests asynchronously, your database will execute all those requests synchronously, so one after the other in the order they came. As node makes the requests asynchronously, the order in which they are executed by your database is not granted, and the issue you are referencing to might happen.
One easy way to avoid this is to use a connection pool which will create a given number of connection, using the same db user. Here are some links that might help you with this :
using a connection pool with node.js
connect a mysql database with node.js

Inserting Values into MySQL DB using NodeJS Not Working

Currently I am experiencing a very frustrating issue with inserting data into my MySQL db using my NodeJS Express server.
My current setup is the following:
• MySQL server db on DigitalOcean droplet.
• NodeJS Express server on the same DigitalOcean droplet. It is being proxied by my Apache server that is on the same droplet. I keep Node server running with PM2.
I have been able to successfully read data from my db (i.e. SELECT * from performance);).
However, no matter what I try I cannot insert any data into my db. I have tried countless different solutions but none have worked.
Help would be greatly appreciated. Please ask any questions for further clarification if needed. Thank you.
My current code relating to MySQL:
server.js
var mysql = require('mysql');
var con = mysql.createConnection({
host: 'localhost',
user: 'user',
password: 'password',
database: 'analytics',
supportBigNumbers: true,
debug: true,
});
server.post('/performance', (req, res) => {
let d = req.body;
con.connect(function (err) {
if (err) throw err;
let q =
'INSERT INTO performance (uid, reqStart, resEnd, loadDuration) VALUES ?';
let values = []; // values to be inserted into db
// for testing purposes I have commented this out and tried inserting a hardcoded set of values instead
/*let body = JSON.parse(req.body); // json string body to json obj
body.data.forEach((x) => {
values.push([body.uid, x.reqStart, x.resEnd, x.loadDuration]);
});*/
values = [
[23299730, 8.3282343284, 8.121252244, 2.238932989],
[23288734, 8.3282343284, 8.121292244, 2.238932989],
];
con.query(q, [values], function (err, result) {
if (err) throw err;
});
});
res.send(d);
});
Update: I just ran my server manually (without PM2). This has allowed me to view console messages. For the first time I have seen a successful insert query. And upon running the server with PM2 I also get a successful query. However, on the second attempt I get PROTOCOL_ENQUEUE_HANDSHAKE_TWICE error.
Based on multiple other posts/articles I thought my code avoided this problem, but it's erroring on the line where I call con.connect(...). I have con.connect in a server.get route, but I haven't been hitting that endpoint at all.
After many hours of debugging, I think I found the problem.
Almost all tutorials showing how to connect to MySQL db using Node show that you should embed a con.query() call within a con.connect() call, and using connect() is recommended on MySQL docs.
However, con.query() also establishes a connection. Maybe it's because I am keeping the server live across multiple calls, but this results in the Handshake error I described in the post. Removing the wrapping con.connect() call fixed my problem.

Connecting to RDS database from node.js

I am trying to learn node.js so that I can actually get started on working on my personal project. I have been trying to follow the examples in the book "Learning node.js" (by Marc Wandschneider). I, at this point, decided to forgo practicing his example, and go straight into using his code as framework for my practice code.
In my practice code, all I am trying to do is connect to my RDS database (no, I am not using Elastic Beanstalk, btw), and output contents of one of the tables. Seems simple enough, but when I whip up the code for it (based on the book), it seems to attempt connection, but get hung up in the process. This is my code:
var pool = require('generic-pool');
var async = require('async');
var mysql = require('mysql');
var host = "<database-name>.cu8hvhstcity.us-west-2.rds.amazonaws.com",
database = "<database-name>",
user = "<username>",
password = "<someLongPassword>";
var dbClient;
async.waterfall([
// 1. establish connection to database
function (callback) {
console.log("Connecting to database " + database + "...");
dbClient = mysql.createConnection({
host: host,
database: database,
user: user,
password: password,
port: 3306
});
dbClient.connect();
},
// 2. select all from a table (let's go for locations)
function (cb)
{
var query = "SELECT * FROM locations"
console.log("running query \"" + query + "\"...");
dbClient.query(query, cb);
},
function (rows, fields, callback)
{
console.log(fields);
for (var i = 0; i < rows.length; i++)
{
console.log(JSON.stringify(rows, null, '\t'));
}
}
], function (err, results) {
if (err)
{
console.log("An error occurred...");
console.log(err);
}
else
{
console.log("Everything successfully completed!");
}
dbClient.end();
})
This is better than first attempt, when I put a database member to the argument passed to mysql.createConnection(), and it complained that database was unknown. In neither case did either "An error occurred..." nor "Everything successfully completed!" output to the window.
Is there any async stuff going on that is resulting in some kind of non-terminating infinite loop or something? How do I fix this?
The book has an associated GitHub page
NOTE:
Neither my example nor the cited GitHub code make use of that pool variable, so it can simply be commented out. All you need to do to run this yourself is to say npm install async,npm install mysql (as well as creating a dummy RDS database to point to, that contains locations table) before copying, pasting, and running this code.
EDIT:
I fixed the issue with database. I realized that the name of the database used '_', not '-'. Same issue (code hangs) still persists...
I did the following:
In the second function in the array, I needed two parameters, not one.
I fixed thus:function(results, cb)
The third function simply needed to callback(null)

MySQL NodeJS Openshift server - query to database seems to not be working

I have a nodejs server in Openshift with a MySQL cartridge. It seems to build with no problem, however, when I try to query the database, it seems to be doing nothing... It doesn't even give me an error, it's just does nothing. Here's my relevant code.
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'mysql://' + process.env.OPENSHIFT_MYSQL_DB_HOST + ':' + process.env.OPENSHIFT_MYSQL_DB_PORT + '/',
user: process.env.OPENSHIFT_MYSQL_DB_USERNAME,
password: process.env.OPENSHIFT_MYSQL_DB_PASSWORD,
database: 'revision',
multipleStatements: true,
debug : true
});
And in the appropriate route:
var stuff = 'abc';
connection.query('SELECT 1', function(err, rows, fields){
if (err) {
stuff = "ghi";
} else {
stuff = "def";
}
});
stuff = stuff + "done";
res.send(JSON.stringify(stuff));
It should return "defdone" or "ghidone", but it always returns "abcdone"... It's like it doesn't even get inside the function. I've tried several ways of doing this and none work. I've dumped the connection variable and it seems to be what's meant to be.
The reason I'm using SELECT 1 as the query string was to verify it was not a database error.
It seems the "issue" had to do with the asynchronous nature of node, as the final 2 instructions are executed before the query is completed. Furthermore, the configs seemed to be wrong after all, as I only had a "host" attribute with the whole url. I changed it into to 2 attributes - "host and "port", giving them the appropriate variables (process.env.OPENSHIFT_MYSQL_DB_HOST and process.env.OPENSHIFT_MYSQL_DB_PORT). It's working now!

MySQL SELECT from one table and INSERT in another - Performance

The situation is: In one http GET request I need to select from one table the information I need and send to the client, and at the same time I need to retrieve the user IP and insert into a database. I'm using Node.js for this experiment.
The thing is: Is there a way to make the two actions together? Or do I have to connect and make two separate queries? Is there a way to render the page and do the other INSERT action in the background? What is the fastest option?
app.get('/', function({
connect.query("SELECT column1, column2 FROM table;", function(err, ...
render("index", ...);
});
connect.query("INSERT INTO table2 SET ip=11111111;");
});
The procedure approach suggested by #skv is nice but you have to wait for the write before doing the read and eventually returning a result to the user.
I would argue for another approach.
Queue the ip-address and a timestamp internally in something like an array or list.
Do the read from the database and return a result to the user
Create a background job that will nibble of the internal array and do the inserts
This has several benefits
The user gets a result faster
The writes can be done later if the system is being called in bursts
The writes can be done in batches of tens or hundreds of inserts reducing the time it takes to write one row.
You can make a stored procedure do this
Basically these are two different operations, but doing it in stored procedures might give you the assurance that it will surely happen, you can pass the IP address as the parameter into the stored procedure, this will also avoid any worries of performance in the code for you as the db takes care of insert, please remember that any select that does not insert into a table or a variable will produce a result set for you to use, hope this helps.
DELIMITER $
CREATE PROCEDURE AddIPandReturnInfo
(
#IPAddress varchar(20)
)
BEGIN
INSERT INTO Yourtable (IPAddress);
SELECT * FROM Tablename;
END $
DELIMITER ;
Well, I assume you're using this module https://github.com/felixge/node-mysql
The MySQL protocol is sequential, then, to execute paralell queries against mysql, you need multiple connections. You can use a Pool to manage the connections.(builtin in the module)
Example:
var mysql = require('mysql');
var pool = mysql.createPool({
host: 'example.org',
user: 'bob',
password: 'secret',
connectionLimit: 5 // maximum number of connections to create at once **10 by default**
});
app.get('/', function (req, res) {
// get a connection from the pool //async
pool.getConnection(function (err, connection) {
// Use the connection
connection.query('SELECT something FROM table1', function (err, rows) {
// Do somethig whith the mysql_response and end the client_response
res.render("index", {...
});
connection.release();
// Don't use the connection here, it has been closed.
});
});
//async
var userIp = req.connection.remoteAddress || req.headers['x-forwarded-for'] || null;
if (userIp) {
// get a connection from the pool again
pool.getConnection(function (err, connection) {
// Use the connection
connection.query('INSERT INTO table2 SET ip=?', [userIp], function (err, rows) {
// And done with the insert.
connection.release(); // Conn Close.
});
});
}
});