-
Hello! This is more of a theoretical question, yet it still pussles me and makes me wonder about the correctness of my code using TransactionScopes. Let's consider this kind of a snippet (let's assume this is a scoped repository, pulling the connection factory from the DI container. Also, we use Dapper - although I guess it would be similar for plain ADO.NET commands): using (var transaction = new TransactionScope())
{
var connection = await _connectionFactory.GetConnection();
var query = "SELECT * .... FOR UPDATE";
var command = new CommandDefinition(query);
var reader = await c.QueryMultipleAsync(command);
var results = await reader.ReadAsync<SomeDto>().ToArray();
if (results.Any(d => d.SomeParam == true))
{
await doUpdate(results, connection); // We do an UPDATE here, skipped
}
transaction.Complete();
} Now, this is a quite typical snippet of code, creating a transaction scope, querying something from the database locking updates to the queried columns during the transaction, then issuing back an update if some condition matches. The actual question is this: from WHERE EXACTLY does the connection knows from where to pull the transaction? In this code, the connection objects never received the transaction object. Now, I do know that there is a notion of Ambient Transaction, and that is where it is stored, and ADO.NET queries it. But WHERE EXACTLY is that Ambient Connection is stored? To what EXACTLY is it tied? First what I thought, is that it is pulled somehow from the DI container - aka opening a transaction scope makes the current DI scope being "inside transaction". But I never found anything supporting this claim. Then, I googled, and found some claims that the ambient transaction is stored in the thread storage. Yet, we're in async world here, there are no guarantees about the SELECT and UPDATE queries ending on the same thread! That couldn't be it, could it? Then, I found out something about distributed transactions and that they leverage some Windows-only functionality. Yet, I'm running my programs mostly under Linux systems, without the need of distributed transactions and yet it still works. So the question is this: where EXACTLY is the Ambient Transaction is actually stored in runtime, and how is it being retrieved? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Answering my own question. |
Beta Was this translation helpful? Give feedback.
Answering my own question.
If TransactionScopeAsyncFlowOption.Enabled is set, it is stored in an AsyncLocal variable aka CallContext. Else it is indeed stored in the thread storage, aka ThreadLocal.