javascript - 如何使用node.js、mssql和msnodesqlv8在事务中正确执行循环查询

标签 javascript sql-server node.js angular

我正在尝试执行我之前在 c# 和 asp.net webforms 中所做的操作,并在事务中执行许多插入存储过程,其中一些在循环中。我现在尝试通过带有 mssql 包的 node.js 在我的 Angular 应用程序中执行此操作。到目前为止我所拥有的内容如下。

    //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

            })
        }
    })
});

网上确实没有太多用于使用存储过程处理事务的 Material ,对于像这样的大型事务则更少。但我在终端日志中多次收到以下错误。

{ 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' }

这无疑表明我执行交易的方式不当。

有人可以帮助指导我如何改进和解决这个问题吗?

编辑:对我的代码进行了更改以反射(reflect)我的发现here ,以及对我的第一个插入内容的一些更改。虽然我的第一次插入确实有效,但我仍然遇到上述重复错误,所以现在我知道我的问题在于如何在循环内实现插入。有没有办法可以在每次插入时关闭连接?这是我应该尝试采取的方法吗?

最佳答案

我最终让它工作起来,虽然我对一切如何工作的理解确实没有多大改善,但我至少可以发布我所拥有的内容,希望对其他人有所帮助。

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." });
                            }
                        });
                    }
                })
        }
    });
})
});

关于javascript - 如何使用node.js、mssql和msnodesqlv8在事务中正确执行循环查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46770777/

相关文章:

javascript - 同步运行函数

php - 如何在 Google App Engine 中包含 PHP 的 MSSQL 驱动程序

sql - 获取家庭成员

javascript - 如何在 Node.js REST API 中处理非传统查询

javascript - 如何导入 socket.io npm 包 - Node Js

javascript - 无法在 React quill 自定义处理程序上调用 ref(还有其他类似状态、 Prop 、函数等)

javascript - 正则表达式中的运算顺序(解决挑战)

sql - T-SQL try ... catch 和多个批处理(2 begin...end,if...else)

javascript - 当目标流发出错误事件时,我们能否以某种方式重用源流?

javascript - 在真假之间切换