【发布时间】:2019-12-31 18:55:05
【问题描述】:
我想创建一个 Express REST API,并将 MSSQL 用于数据库部分。我使用mssql 模块并使用PreparedStatement 类。
有时我的查询必须是事务性的,所以我也必须使用 Transaction 类。
我找到了一些关于预处理语句here 和事务here 的信息,但不知道如何使用预处理语句执行事务查询。
有人介意解释如何在事务中使用带有准备好的语句的 mssql 模块吗?我的查询函数应该提供一种功能,可以在我的查询文件中写入类似这样的内容
- 开始交易
- 运行准备好的语句一
- 运行准备好的语句二
- 结束交易
所以要重现问题: 首先,我创建了一个数据库,其中包含一个名为“integer”的表和一个数字列“value”。
然后我用这段代码创建了一个空的 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;
});
到目前为止一切顺利。现在我想在一个事务中运行两个 INSERT,但第二个传入一个字符串,所以我预计会出现错误,第一个会回滚。我更新的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;
}
}
现在我收到此错误
(node:18416) UnhandledPromiseRejectionWarning: TransactionError: Can't 回滚事务。有一个请求正在进行中。
而且我不确定我的语法是否错误。
【问题讨论】:
-
您发布的链接显示“提示:您还可以在事务中创建准备好的语句(新 sql.PreparedStatement(transaction)),但请记住您不能在事务中执行其他请求直到你打电话给 unprepare。”,这似乎很清楚。您在让它工作或将其集成到您的
IDatabase设计中时遇到问题吗? -
谢谢@Nickolay。是的,我需要帮助进行设置。我知道我可以将事务传递给准备好的语句,但是我将如何链接我的准备好的语句执行?您介意提供一个包含带有多个预准备语句的事务的示例代码吗?
-
FWIW 我仍然不确定我是否理解您的问题,特别是考虑到问题的最新编辑 - 我认为您可以简单地将
transaction对象代替this.connectionPool传递给PreparedStatement。也许分享使用无效交易的尝试会带来一些清晰。 -
@Nickolay 我希望这次编辑能解决我的问题 :)
标签: javascript node.js sql-server typescript node-mssql