简体   繁体   中英

How to perform looped queries in transactions properly with node.js, mssql and msnodesqlv8

I am attempting to do what I've previously done in c# and asp.net webforms and execute a number of insert stored procedures, some of which are in loops, in a transaction. I am now trying to do so in my angular application through node.js with the mssql package. What I have so far is as follows.

    //Insert Change Record
router.post('/insertChange', (req, res) => {
    const transaction = new sql.Transaction(conn);

    transaction.begin(err => {
        let rolledBack = false;
        transaction.on('rollback', aborted => {
            rolledBack = true;
        })
        const request = new sql.Request(transaction);
        request.input('ChangeTitle', req.body.changeTitle);
        request.input('TypeId', req.body.typeId);
        request.input('DateSubmitted', req.body.dateSubmitted);
        request.input('TargetDate', req.body.targetProductionDate);

        request.input('ChangeSponsor', req.body.changeSponsor);
        request.input('UATDate', req.body.dateReadyUAT);
        request.input('ChangeSponsorEmail', req.body.changeSponsorEmail);
        request.input('ClarityId', req.body.clarityId);
        request.input('ChangeDescription', req.body.changeDescription);

        request.input('ComponentName', req.body.componentName);
        request.input('ComponentDescription', req.body.componentDescription);

        request.input('ReasonForChange', req.body.reasonForChange);
        request.input('ComponentREplacing', req.body.componentReplacing);
        request.input('DependentChange', req.body.dependentChange);

        request.input('InstallOption', req.body.installOption);
        request.input('RebootRequired', req.body.rebootRequired);
        request.input('UserIntervention', req.body.userIntervention);
        request.input('Activation', req.body.activation);

        request.input('ContingencyPlan', req.body.contingencyPlan);
        request.input('AdditionalInformation', req.body.additionalInformation);

        request.input('PerformanceImpact', req.body.applicationPerformance);
        request.input('IsPCoERequired', req.body.pcoeTesting);
        request.input('IsCanadianRetailBranch', req.body.pbsTesting);

        request.input('BusinessAppImpact', req.body.businessApplication);
        request.input('NetworkImpact', req.body.networkPerformance);
        request.input('NewInfrastructure', req.body.newInfrastructure);
        request.input('LogonTime', req.body.logonTime);
        request.input('AdditionalTechnicalInformation', req.body.additionalAssessmentInfo);

        request.input('IsProdIssue', req.body.isProdIssue);
        request.input('ProdIssue', req.body.productionIssue);
        request.input('ProdIncidentNum', req.body.incidentNumbers);
        request.input('IsMajorChange', req.body.isMajorChange);
        request.input('HasRequiredTesting', req.body.hasRequiredTesting);
        request.input('HasPackageSubmit', req.body.hasPackageSubmit);
        request.input('SignOffETA', req.body.signoffETA);
        request.input('SpecificTesting', req.body.specificTesting);
        request.input('SpecificPilot', req.body.specificPilot);
        request.input('PilotInfo', req.body.pilotTransits);

        request.input('UserChanges', req.body.userDifferences);
        request.input('ServiceDeskProcedure', req.body.procedureSupport);
        request.input('SupportCallFlowId', req.body.supportCallFlow);

        request.input('OverallChangeStatus', 1);

        let changeId = request.output('changeId', sql.Int);

        request.execute('dbo.InsertChange').then(function (result) {
            console.dir(result);
        }).catch(function (err) {
            console.dir(err);
        });

        async.each(
            req.body.changeType
            ,function iterator(item, next) {
            const requestCT = new sql.Request(transaction);
            requestCT.input('ChangeId', changeId);
            requestCT.input('TypeOfChangeId', item.typeOfChangeId);
            requestCT.input('Description', item.description);
            requestCT.execute('dbo.InsertTypeOfChange').then(function (result) {
                console.dir(result);
                next();
            }).catch(function (err) {
                console.dir(err);
            });
        })
        async.each(
            req.body.serviceImpacted
            ,function iterator(item, next) {
            const requestSI = new sql.Request(transaction);
            requestSI.input('ChangeId', changeId);
            requestSI.input('ServicesImpactedId', item.serviceImpactedId);
            requestSI.execute('dbo.InsertImpactedService').then(function (result) {
                console.dir(result);
                next();
            }).catch(function (err) {
                console.dir(err);
            });
        })
        async.each(
            req.body.businessImpacted
            ,function iterator(item, next) {
            const requestBI = new sql.Request(transaction);
            requestBI.input('ChangeId', changeId);
            requestBI.input('BusinessImpactedId', item.businessImpactedId);
            requestBI.execute('dbo.InsertImpactedBusiness').then(function (result) {
                console.dir(result);
                next();
            }).catch(function (err) {
                console.dir(err);
            });
        })
        async.each(
            req.body.criticalApp
            ,function iterator(item, next) {
            const requestCA = new sql.Request(transaction);
            requestCA.input('ChangeId', changeId);
            requestCA.input('CriticalBankingId', item.criticalId);
            requestCA.input('Description', item.description);
            requestCA.execute('dbo.InsertCriticalBankingApp').then(function (result) {
                console.dir(result);
                next();
            }).catch(function (err) {
                console.dir(err);
            });
        })
        async.each(
            req.body.testStages
            ,function iterator(item, next) {
            const requestTS = new sql.Request(transaction);
            requestTS.input('ChangeId', changeId);
            requestTS.input('TestStageId', item.testStageId);
            requestTS.input('TestDate', item.testDate);
            requestTS.input('Description', item.description);
            requestTS.execute('dbo.InsertChangeTest').then(function (result) {
                console.dir(result);
                next();
            }).catch(function (err) {
                console.dir(err);
            });
        })

        if (err) {
            if (!rolledBack) {
                transaction.rollback(err => {
                    console.dir(err);
                    // ... error checks
                })
            }
        } else {
            transaction.commit(err => {
                console.dir(err);
                // ... error checks

            })
        }
    })
});

There really isn't a heck of a lot of material online anywhere for processing transactions with stored procedures, and even less for big transactions like this. But the error I'm getting is the following multiple times in my terminal log.

{ TransactionError: Can't acquire connection for the request. There is another request in progress.
at Transaction.acquire (C:\Users\Redirection\meecd26\Documents\GitRepo\td-angular-starter\node_modules\mssql\lib\base.js:740:30)
at Immediate._query.err [as _onImmediate] (C:\Users\Redirection\meecd26\Documents\GitRepo\td-angular-starter\node_modules\mssql\lib\msnodesqlv8.js:417:19)
at runCallback (timers.js:781:20)
at tryOnImmediate (timers.js:743:5)
at processImmediate [as _immediateCallback] (timers.js:714:5) code: 'EREQINPROG', name: 'TransactionError' }

This certainly suggests that I'm performing the transaction improperly.

Would someone be able to help guide me as to how I can improve and fix this?

Edit: Made changes to my code to reflect what I found here , as well as a few changes to my first insert. While my first insert does work, I'm still getting the repeated errors above, so now I know my problems are with how I'm implementing the inserts inside of loops. Is there a way I can close the connection upon each insert? Would that be the approach I should try and take?

I ended up getting it working, and although my understanding of how everything works admittedly hasn't improved much at all, I can at least post what I have in hopes of others hopefully finding it helpful.

router.post('/insertChange', (req, res) => {
console.log("Beginning of POST, before initializing transaction");

let changeId;
let mainInsert = false;

beginTransaction(function (err, rollback, transaction) {
    if (err) {
        // return cb(err);
    }
    let request = new sql.Request(transaction);
    // request.verbose = true;
    request.input('ChangeTitle', req.body.ChangeTitle);
    request.input('TypeId', req.body.TypeId);
    request.input('DateSubmitted', req.body.DateSubmitted);
    request.input('TargetDate', req.body.TargetDate);

    request.input('ChangeSponsor', req.body.ChangeSponsor);
    request.input('UATDate', req.body.UATDate);
    request.input('ChangeSponsorEmail', req.body.ChangeSponsorEmail);
    request.input('ClarityId', req.body.ClarityId);
    request.input('ChangeDescription', req.body.ChangeDescription);

    request.input('ComponentName', req.body.ComponentName);
    request.input('ComponentDescription', req.body.ComponentDescription);

    request.input('ReasonForChange', req.body.ReasonForChange);
    request.input('ComponentReplacing', req.body.ComponentReplacing);
    request.input('DependentChange', req.body.DependentChange);

    request.input('InstallOption', req.body.InstallOption);
    request.input('RebootRequired', req.body.RebootRequired);
    request.input('UserIntervention', req.body.UserIntervention);
    request.input('Activation', req.body.Activation);

    request.input('ContingencyPlan', req.body.ContingencyPlan);
    request.input('AdditionalInformation', req.body.AdditionalInformation);

    request.input('PerformanceImpact', req.body.PerformanceImpact);
    request.input('IsPCoERequired', req.body.IsPCoERequired);
    request.input('IsCanadianRetailBranch', req.body.IsCanadianRetailBranch);

    request.input('BusinessAppImpact', req.body.BusinessAppImpact);
    request.input('NetworkImpact', req.body.NetworkImpact);
    request.input('NewInfrastructure', req.body.NewInfrastructure);
    request.input('LogonTime', req.body.LogonTime);
    request.input('AdditionalTechnicalInformation', req.body.AdditionalTechnicalInformation);

    request.input('IsProdIssue', req.body.IsProdIssue);
    request.input('ProdIssue', req.body.ProdIssue);
    request.input('ProdIncidentNum', req.body.ProdIncidentNum);
    request.input('IsMajorChange', req.body.IsMajorChange);
    request.input('HasRequiredTesting', req.body.HasRequiredTesting);
    request.input('HasPackageSubmit', req.body.HasPackageSubmit);
    request.input('SignOffETA', req.body.SignOffETA);
    request.input('SpecificTesting', req.body.SpecificTesting);
    request.input('SpecificPilot', req.body.SpecificPilot);
    request.input('PilotInfo', req.body.PilotInfo);

    request.input('UserChanges', req.body.UserChanges);
    request.input('ServiceDeskProcedure', req.body.ServiceDeskProcedure);
    request.input('SupportCallFlowId', req.body.SupportCallFlowId);

    request.input('OverallChangeStatus', 1);

    request.output('changeId', sql.Int);

    request.execute('dbo.InsertChange', function (err, callback) {
        if (err) {
            console.dir(err);
            rollback(err);
            res.status(400).send("Failed to submit change form.");

        } else {
            mainInsert = true;
        }

        if (callback) {
            changeId = +callback.returnValue;
        }

        if (mainInsert) {
            async.each(
                req.body.changeType, function iterator(item, next) {
                    request = new sql.Request(transaction);
                    request.input('ChangeId', changeId);
                    request.input('TypeOfChangeId', item.typeOfChangeId);
                    request.input('Description', item.description);
                    request.execute('dbo.InsertTypeOfChange', function (err, callback) {
                        if (err) return next(err);
                        console.dir(callback);
                        next();
                    })
                }, function fin(err) {
                    if (err) {
                        rollback(err);
                        return; //done
                    }
                })
            async.each(
                req.body.serviceImpacted, function iterator(item, next) {
                    request = new sql.Request(transaction);
                    request.input('ChangeId', changeId);
                    request.input('ServicesImpactedId', item.serviceImpactedId);
                    request.execute('dbo.InsertImpactedService', function (err, callback) {
                        if (err) return next(err);
                        console.dir(callback);
                        next();
                    })
                }, function fin(err) {
                    if (err) {
                        rollback(err);
                        return; //done
                    }
                })
            async.each(
                req.body.businessImpacted, function iterator(item, next) {
                    request = new sql.Request(transaction);
                    request.input('ChangeId', changeId);
                    request.input('BusinessImpactedId', item.businessImpactedId);
                    request.execute('dbo.InsertImpactedBusiness', function (err, callback) {
                        if (err) return next(err);
                        console.dir(callback);
                        next();
                    })
                }, function fin(err) {
                    if (err) {
                        rollback(err);
                        return; //done
                    }
                })
            async.each(
                req.body.criticalApp, function iterator(item, next) {
                    request = new sql.Request(transaction);
                    request.input('ChangeId', changeId);
                    request.input('CriticalBankingId', item.criticalId);
                    request.input('Description', item.description);
                    request.execute('dbo.InsertCriticalBankingApp', function (err, callback) {
                        if (err) return next(err);
                        console.dir(callback);
                        next();
                    })
                }, function fin(err) {
                    if (err) {
                        rollback(err);
                        return; //done
                    }
                })
            async.each(
                req.body.testStages, function iterator(item, next) {
                    request = new sql.Request(transaction);
                    request.input('ChangeId', changeId);
                    request.input('TestStageId', item.testStageId);
                    request.input('TestDate', item.testDate);
                    request.input('Description', item.description);
                    request.execute('dbo.InsertChangeTest', function (err, callback) {
                        if (err) return next(err);
                        console.dir(callback);
                        next();
                    })
                }, function fin(err) {
                    if (err) {
                        rollback(err);
                        return; //done
                    }
                    else {
                        transaction.commit(function (err) {
                            if (err) {
                                console.error('Transaction commit error: ', err);
                                res.status(400).send("Failed to submit change form.");
                            } else {
                                console.error('Transaction commit success');
                                res.send({ "Response": "Success", "Message": "Change form successfully submitted." });
                            }
                        });
                    }
                })
        }
    });
})
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM