为了阐明我在让nodejs/mssql应用程序工作时遇到的问题,我尝试编写了包装在事务中的简单(准备好的)INSERT语句的两个功能等效版本。
回调版本有效 - 在我的 Sql Server 数据库中插入一行。
异步/等待版本抛出错误-
TransactionError: Can't commit transaction. There is a request in progress.
我已经尝试了失败版本的许多变体(在可行的地方重新排序语句),但下面包含的版本是最接近模仿工作回调版本逻辑的版本。
谢谢!
var sql = require('mssql'); // mssql: 4.1.0; tedious: 2.2.4; node: v8.4.0
var cfg = {
"db": "sqlserver",
"domain": "XXXXXX",
"user": "cseelig",
"password": "xxxxxx",
"server": "xxxxxx.xxxxxx.xxxxxx.xxxxxx",
"port": 1433,
"stream": false,
"options": {
"trustedConnection": true
},
"requestTimeout": 900000,
"connectionTimeout": 30000,
"pool": {
"max": 3,
"min": 0,
"idleTimeoutMillis": 30000
}
};
var statement = "insert into wng_dw.dbo.D_LIB_Google_Search_Query (query, LastUpdateDate) values (@query, GetDate())";
// I only run one or the other -
main1("12347"); // fails
main2("98765:); // works
async function main1(val) {
try {
const conn = await new sql.connect(cfg);
const transaction = new sql.Transaction();
await transaction.begin();
const ps = new sql.PreparedStatement(transaction);
ps.input('query', sql.VarChar(200));
await ps.prepare(statement);
await ps.execute( {"query": val} );
await ps.unprepare();
await transaction.commit();
sql.close;
} catch(err){
console.log("Error: " + err);
};
process.exit(0);
}
async function main2(val) {
sql.connect(cfg, err => {
const transaction = new sql.Transaction();
transaction.begin(err => {
const ps = new sql.PreparedStatement(transaction);
ps.input('query', sql.VarChar(200));
ps.prepare(statement, err => {
ps.execute( {"query": val}, (err, result) => {
ps.unprepare(err => {
transaction.commit(err => {
sql.close();
});
});
});
});
});
});
}
在提交或回滚事务之前,必须取消所有语句。
您还必须等待未准备好的语句,否则请求仍在进行中,执行promise尚未解决。
使用一个小包装使事情变得简单:
import * as dotenv from 'dotenv'
import mssql from 'mssql'
dotenv.config()
const sqlServerConfig = {
server: process.env.SQL_SERVER,
user: process.env.QS_USER,
password: process.env.QS_PASS,
options: { enableArithAbort: false },
}
let pool: mssql.ConnectionPool
let transaction: mssql.Transaction
const statements: mssql.PreparedStatement[] = []
export const connect = async (): Promise<void> => {
pool = new mssql.ConnectionPool({ ...sqlServerConfig, database: process.env.DATABASE })
await pool.connect()
}
export const disconnect = async (): Promise<void> => {
if (typeof pool == 'undefined') return
if (pool.connected) await pool.close()
}
export const begin = async (): Promise<void> => {
transaction = new mssql.Transaction(pool)
await transaction.begin()
}
export const unprepare = async (statement: mssql.PreparedStatement): Promise<void> => {
if (typeof statement == 'undefined') return
if (statement.prepared) await statement.unprepare()
}
export const commit = async (): Promise<void> => {
await transaction.commit()
}
export const rollback = async (): Promise<void> => {
for (const statement of statements) {
await unprepare(statement)
}
if (typeof transaction == 'undefined') return
await transaction.rollback()
}
export const createStatement = (): mssql.PreparedStatement => {
const statement = new mssql.PreparedStatement(transaction)
statements.push(statement)
return statement
}
用法:
try {
await connect()
await begin()
const myStatement = createStatement()
..... bind parameters
..... prepare statement
for ( ..... ) {
await myStatement.execute( ..... )
}
await unprepare(myStatement)
await commit()
await disconnect()
exit(0)
}
catch(e) {
log.error(e)
await rollback()
await disconnect()
exit(1)
}
您可以使用create语句()创建一个准备好的语句。create语句会跟踪语句,因此在您回滚的情况下,当您调用回滚时,它们将不会为您准备好。
交易。开始不返回promise。你可以简单地答应。如下所示:
await new Promise(resolve => transaction.begin(resolve));
const request = new sql.Request(transaction);
//...
await transaction.commit();
提交和回滚后,“请求”对象不能再使用。否则,它将显示有关交易未开始的错误....
希望对此有所帮助。
问题内容: 在节点版本8中可用。该代码本来是在nodejs中第一次线性执行。那很好。早先的许多文章声称,在v8 javascript引擎中,带有block 的函数未优化。现在,需要块来处理错误。那么,作为开发人员,需要做些什么来保持相同的性能? 问题答案: 在针对V8 (节点及更高版本)的提交中获得了TurboFan优化。这意味着具有不良性能的历史性说法不再正确。 从V8博客文章: 过去,V8难以
我试图在ubuntu服务器上安装npm和nodejs,但注意到不知何故,在运行后,我最终得到了两个版本。我知道这一点,因为当我运行时,它会返回,而当我运行时,它返回。在我继续之前,我想把这个设置好。有人明白我为什么会有两个版本吗?我的理解是,安装nodejs也应该安装npm,但这只允许我以更高的权限运行npm,我知道我不应该这样做。谁能让我知道我做错了什么?谢谢你。
我最近发布了一个应用程序。现在我正在努力更新它。 我遇到了一个问题。我得到一个错误: 上载失败您需要为APK使用其他版本代码,因为您已经有一个版本代码为1的版本 现在我做了一些研究并尝试了各种方法,下面是我发现并尝试的结果列表: 我已经将版本代码更改为许多不同的东西,但都不起作用,对于所有这些东西都是相同的错误,如果我将版本代码设置为3,错误仍然表示我已经有一个版本代码为1的文件,并且它从来没有其
问题内容: 在Java中制作异步方法的同步版本的最佳方法是什么? 假设您有一个使用以下两种方法的类: 您将如何实现直到任务完成才返回的同步? 问题答案: 看看CountDownLatch。您可以使用以下类似方式模拟所需的同步行为: 您还可以通过2个参与者使用相同的行为,如下所示: 但是,如果您可以控制I 的源代码,建议您重新设计它以返回一个对象。这样,您可以在需要时轻松地在异步/同步行为之间进行切
我在实验在不同的关键字和运算符周围是如何解释的,发现以下语法是完全合法的: 错误: 未捕获的引用错误:等待未定义 它似乎试图将解析为变量名。。?我期待着 或者是类似于 意外令牌等待 令我恐惧的是,你甚至可以给它分配一些东西: 如此明显错误的东西不应该导致语法错误吗,就像,,等一样?为什么允许这样做,以及第一个片段中到底发生了什么?
我正在使用Maven构建一个Hadoop项目,并在http://search.Maven.org/中搜索依赖项。 Hadoop-common的结果只包括版本0.2x和2.x,那么版本1.x呢? 希望得到详细的解释。