简体   繁体   English

使用 Node mssql 处理准备好的语句

[英]Transaction for prepared statements using Node mssql

I want to create an Express REST API and will use MSSQL for the database part.我想创建一个 Express REST API,并将使用 MSSQL 作为数据库部分。 I use the mssql module and use the PreparedStatement class.我使用mssql模块并使用PreparedStatement类。

Sometimes my queries have to be transactional, so I have to work with the Transaction class too.有时我的查询必须是事务性的,所以我也必须使用Transaction类。

I found some information about prepared statements here and about transactions here but don't know how to execute transactional queries using prepared statements.我在这里找到了一些关于准备好的语句和事务的信息,但不知道如何使用准备好的语句执行事务查询。

Would someone mind explaining how to use the mssql module with prepared statements within transactions?有人介意解释如何在事务中使用带有准备好的语句的 mssql 模块吗? My query function should provide a functionality giving access to write something like this in my query file我的查询功能应该提供一个功能,允许在我的查询文件中写入这样的内容

  • begin transaction开始交易
  • run prepared statement one运行准备好的语句一
  • run prepared statement two运行准备好的语句二
  • end transaction结束交易

So to reproduce the problem: First I created a database with a table called "integer" and a numeric column "value".所以要重现这个问题:首先,我创建了一个数据库,其中包含一个名为“整数”的表和一个数字列“值”。

Then I created an empty Node/Typescript project with this code:然后我使用以下代码创建了一个空的 Node/Typescript 项目:

import sql, { ConnectionPool, PreparedStatement } from 'mssql';

class App {
    private connectionPool: ConnectionPool;

    constructor() {
        this.connectionPool = new sql.ConnectionPool(databaseConfig);
    }

    public run = async (): Promise<void> => {
        try {
            await this.connectionPool.connect();

            const preparedStatement: PreparedStatement = new sql.PreparedStatement(this.connectionPool);

            preparedStatement.input('number', sql.Numeric(18, 0));

            await preparedStatement.prepare('INSERT INTO integer (value) VALUES (@number)');
            await preparedStatement.execute({ number: 1 });
            await preparedStatement.unprepare();

            console.log('done...');
        } catch (error) {
            throw error;
        }
    }
}

(async () => {
    const app: App = new App();
    await app.run();
})().catch(error => {
    throw error;
});

So far so good.到现在为止还挺好。 Now I want to run two INSERTs within a transaction but the second one passes in a string so I would expect an error and the first one gets rolled back.现在我想在一个事务中运行两个 INSERT,但第二个传入一个字符串,所以我预计会出现错误并且第一个被回滚。 My updated run function:我更新的run功能:

public run = async (): Promise<void> => {
    try {
        await this.connectionPool.connect();

        const transaction: Transaction = new sql.Transaction(this.connectionPool);

        const workingStatement: PreparedStatement = new sql.PreparedStatement(transaction);
        workingStatement.input('number', sql.Numeric(18, 0));

        const invalidStatement: PreparedStatement = new sql.PreparedStatement(transaction);
        invalidStatement.input('number', sql.Numeric(18, 0));

        try {
            await transaction.begin();

            await workingStatement.prepare('INSERT INTO integer (value) VALUES (@number)');
            await workingStatement.execute({ number: 1 });
            await workingStatement.unprepare();

            await invalidStatement.prepare('INSERT INTO integer (value) VALUES (@number)');
            await invalidStatement.execute({ number: false });
            await invalidStatement.unprepare();

            await transaction.commit();
        } catch (error) {
            await transaction.rollback();
            console.log('execution failed...');
        }

        console.log('done...');
    } catch (error) {
        throw error;
    }
}

Now I get this error现在我收到这个错误

(node:18416) UnhandledPromiseRejectionWarning: TransactionError: Can't rollback transaction. (节点:18416)未处理的PromiseRejectionWarning:TransactionError:无法回滚事务。 There is a request in progress.有一个请求正在进行中。

And I'm not sure if my syntax is wrong.而且我不确定我的语法是否错误。

I believe the error you're hitting happens because you didn't call unprepare as suggested in the docs:我相信您遇到的错误是因为您没有按照文档中的建议调用unprepare

keep in mind you can't execute other requests in the transaction until you call unprepare请记住,在调用 unprepare 之前,您无法执行事务中的其他请求

Calling unprepare on the statement before rolling back the transaction works for me:在回滚事务之前对语句调用unprepare对我有用:

try {
  // ...
  await invalidStatement.prepare('INSERT INTO integer (value) VALUES (@number)');
  try {
    await invalidStatement.execute({ number: false });
  } finally {
    await invalidStatement.unprepare();
  }
} catch (error) {
  // rollback here...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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