question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

make transactions to wait multiple queries and execute them in a proper order

See original GitHub issue

Im migrating from v3 and v4 and now I have

TransactionError: Can't acquire connection for the request. There is another request in progress.

errors. Is it related to Transaction and PreparedStatement internal queues was removed release change somehow? If yes, then can you explain what it means?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:3
  • Comments:19 (1 by maintainers)

github_iconTop GitHub Comments

8reactions
dhensbycommented, Jan 26, 2020

Just to labour the point here: Transactions are connection specific and so all queries in the context of a Transaction have to happen over a single database connection. Likewise, a single connection can only run one query at a time, so queries over one connection need to be run in sequence, not in parallel. The only way you can run queries in parallel is by using more than one connection at a time. Therefore, it is not possible to run parallel queries in the context of a Transaction.

Consider the following example:

const mssql = require('mssql');

async function runTransaction(pool) {
  const transaction = new mssql.Transaction(pool);
  await transaction.begin();
  const req = new mssql.Request(transaction);
  await req.query('INSERT INTO companies (name, active) VALUES ('Microsoft', false);');
  // get all users and get all companies
  // this will fail because you can't run the queries in parallel, there is only a single connection to run on
  const [companies, users] = await Promise.all([
    req.query('SELECT * FROM companies;'),
    req.query('SELECT * FROM users;'),
  ]);
  // instead we have to do this because we only have one connection
  const companies = await req.query('SELECT * FROM companies;'); // this will include the company 'Microsoft' because we are in the transaction
  const users = await req.query('SELECT * FROM users;');
  ...
  await transaction.commit();
}

If we want to run queries in parallel, then we need to run the queries against the pool, but we must accept that the changes we’ve made so far in the transaction will not be reflected in our results:

  const [companies, users] = await Promise.all([
    pool.query('SELECT * FROM companies;'), // this will not include the company 'Microsoft' because it is being run over a connection that does not have the transaction context
    pool.query('SELECT * FROM users;'),
  ]);

You cannot run multiple queries, in parallel, over a single connection. It is for the developer to understand the limitations of transactions and the fact they are performed over a single connection, the parallel execution of the queries is simply not possible in a transaction. The only other option would be to allow the apparent execution of requests in parallel but internally we simply queue the queries and execute the sequentially. This is something I’m considering but it does not solve the underlying issue that they will not and cannot be run in parallel over a single connection.

8reactions
samjrosscommented, May 16, 2019

Since this is the top-level google result for TransactionError: Can't acquire connection for the request. There is another request in progress., I thought I’d give my solution to people, given my context:

I have an app which starts a transaction, and a transaction.request(), and passes the transactionRequest around to different functions which all add onto it, via stuff like await transactionRequest.query`INSERT...`

I use the library await-lock to make this easier – when I first make the transaction, and the transactionRequest that I will later pass on to all the other functions, I add a _lock onto the transactionRequest, transactionRequest._lock = new AwaitLock();, and then every time I want to use the transactionRequest, I’ll first do await transactionRequst._lock.acquireAsync() and then make sure I release it later, in a try{}finally{ transactionRequst._lock.release() }

This has worked a treat

Read more comments on GitHub >

github_iconTop Results From Across the Web

Transactions in SQL Server for beginners
This article will show basic principles of transactions in SQL Server with examples.
Read more >
Transaction locking and row versioning guide - SQL Server
Each transaction requests locks of different types on the resources, such as rows, pages, or tables, on which the transaction is dependent. The ......
Read more >
Running Multiple Queries in Oracle SQL Developer
After you run send your query to Oracle, it has to do 3 things: ... and the database know that there are more...
Read more >
SQL Performance Best Practices | CockroachDB Docs
The statement orders transactions by controlling concurrent access to one or more rows of a table. It works by locking the rows returned...
Read more >
Transactions and batch queries (Reference) - Prisma
Sometimes you need more control over what queries execute within a transaction. Interactive transactions are meant to provide you with an escape hatch....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found