使用 Node mssql 准备语句的事务
Transaction for prepared statements using Node mssql
我想创建一个 Express REST API 并将 MSSQL 用于数据库部分。我使用 mssql 模块并使用 PreparedStatement
class。
有时我的查询必须是事务性的,所以我也必须使用 Transaction
class。
我找到了一些有关准备语句的信息here and about transactions here,但不知道如何使用准备语句执行事务查询。
有人介意解释一下如何在事务中将 mssql 模块与准备好的语句一起使用吗?我的查询函数应该提供一个功能,允许在我的查询文件中写这样的东西
- 开始交易
- 运行准备语句一
- 运行准备语句二
- 结束交易
所以要重现问题:
首先,我创建了一个数据库,其中包含一个名为 "integer" 的 table 和一个数字列 "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
rollback transaction. There is a request in progress.
而且我不确定我的语法是否有误。
我相信您遇到的错误是因为您没有按照文档中的建议调用 unprepare
:
keep in mind you can't execute other requests in the transaction until you call unprepare
在回滚事务之前对语句调用 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...
}
我想创建一个 Express REST API 并将 MSSQL 用于数据库部分。我使用 mssql 模块并使用 PreparedStatement
class。
有时我的查询必须是事务性的,所以我也必须使用 Transaction
class。
我找到了一些有关准备语句的信息here and about transactions here,但不知道如何使用准备语句执行事务查询。
有人介意解释一下如何在事务中将 mssql 模块与准备好的语句一起使用吗?我的查询函数应该提供一个功能,允许在我的查询文件中写这样的东西
- 开始交易
- 运行准备语句一
- 运行准备语句二
- 结束交易
所以要重现问题: 首先,我创建了一个数据库,其中包含一个名为 "integer" 的 table 和一个数字列 "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 rollback transaction. There is a request in progress.
而且我不确定我的语法是否有误。
我相信您遇到的错误是因为您没有按照文档中的建议调用 unprepare
:
keep in mind you can't execute other requests in the transaction until you call unprepare
在回滚事务之前对语句调用 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...
}