Nodejs mysql transaction rollback not working
I am using Nodejs MySQL and tried to create database level transaction so that I can execute a bunch of statements in a batch and rollback if there is an error in any step. I tried to follow this tutorial.
My database module is:
let mysql = require('mysql') let keys = require('../config/keys') let util = require('util') let pool = mysql.createPool({ connectionLimit: 20, host: keys.connection.host, user: keys.connection.user, password: keys.connection.password, database: keys.connection.database, dateStrings: true // debug:true //Set this to true for verbose debugging. Leaving this to default for now cause it is creating too many messages at my console }) pool.getConnection((err, connection) => { if (err) { if (err.code === 'PROTOCOL_CONNECTION_LOST') { console.error('Database connection was closed.') } if (err.code === 'ER_CON_COUNT_ERROR') { console.error('Database has too many connections.') } if (err.code === 'ECONNREFUSED') { console.error('Database connection was refused.') } } if (connection) connection.release() return }) pool.query = util.promisify(pool.query) const connection = () => { return new Promise((resolve, reject) => { pool.getConnection((err, connection) => { if (err) reject(err); console.log("MySQL pool connected: threadId " + connection.threadId); const query = (sql, binding) => { return new Promise((resolve, reject) => { connection.query(sql, binding, (err, result) => { if (err) reject(err); resolve(result); }); }); }; const release = () => { return new Promise((resolve, reject) => { if (err) reject(err); console.log("MySQL pool released: threadId " + connection.threadId); resolve(connection.release()); }); }; resolve({ query, release }); }); }); }; // const query = (sql, binding) => { // return new Promise((resolve, reject) => { // pool.query(sql, binding, (err, result, fields) => { // if (err) reject(err); // resolve(result); // }); // }); // }; module.exports = { pool, connection }
In my route, I am trying to use the connection which should allow transaction:
const mysql = require('../../middleware/database') async function buildCoreSchemas(){ const connection = await mysql.connection(); try{ await connection.query("START TRANSACTION"); await connection.query(`CREATE TABLE adjustreason ( AdjustID int NOT NULL AUTO_INCREMENT, AdjustReason varchar(100) NOT NULL, PRIMARY KEY (AdjustID) )`) await connection.query(`insert into adjustreason(AdjustReason) values('sdsds')`) await connection.query(`insert into adjustreason(FAKECOLUMN) values('sdsds')`) await connection.query("COMMIT"); } catch(err){ await connection.query("ROLLBACK"); console.log(err) return false } finally { await connection.release(); }
As you can see I my second insert statement is wrong as there is no column name called FAKE COLUMN
. So, the error gets caught and I get the error message in my console:
Unknown column ‘FAKECOLUMN’ in ‘field list
But when I go and look at my database the transaction is not rollbacked because I can see that the first record is still there. What am I doing wrong?
Ciao, try to modify code in this way:
connection.beginTransaction(function(err) { if (err) { throw err; } connection.query(`CREATE TABLE adjustreason ( AdjustID int NOT NULL AUTO_INCREMENT, AdjustReason varchar(100) NOT NULL, PRIMARY KEY (AdjustID) )`, function (error, results, fields) { if (error) { return connection.rollback(function() { throw error; }); } connection.query(`insert into adjustreason(AdjustReason) values('sdsds')`, function (error, results, fields) { if (error) { return connection.rollback(function() { throw error; }); } connection.query(`insert into adjustreason(FAKECOLUMN) values('sdsds')`, function (error, results, fields) { if (error) { return connection.rollback(function() { throw error; }); } connection.commit(function(err) { if (err) { return connection.rollback(function() { throw err; }); } console.log('success!'); }); }); }); }); });
so you call connection.query inside connection.beginTransaction and if one of those query fails, you call connection.rollback. Otherwise connection.commit