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.

SqlTransaction and TransactionScope leak isolation level

See original GitHub issue

The TransactionScope class seems to “leak” it’s isolation level to future queries on the same (pooled) connection.

I would expect the isolation level of the connection to be restored when the transaction ends or is disposed.

Here is a snippet which reproduces the behavior:

SqlConnection.ClearAllPools();
var conn = new SqlConnection(new SqlConnectionStringBuilder { DataSource = @".\sqlexpress", IntegratedSecurity = true }.ConnectionString);

Action printIsolationLevel = () =>
{
	var cmd = conn.CreateCommand();
	cmd.CommandText = @"SELECT CASE transaction_isolation_level 
						WHEN 0 THEN 'Unspecified' 
						WHEN 1 THEN 'ReadUncommitted' 
						WHEN 2 THEN 'ReadCommitted' 
						WHEN 3 THEN 'Repeatable' 
						WHEN 4 THEN 'Serializable' 
						WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL 
						FROM sys.dm_exec_sessions 
						where session_id = @@SPID";
	Console.WriteLine(cmd.ExecuteScalar());
};

conn.Open();
printIsolationLevel(); // "ReadCommitted"
conn.Close();

using (var scope = new TransactionScope(
					TransactionScopeOption.RequiresNew,
					new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.Serializable }))
{
	conn.Open();
	printIsolationLevel(); // "Serializable"
	conn.Close();
}

conn.Open();
printIsolationLevel(); // "Serializable" !!?
conn.Close();

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:8
  • Comments:20 (11 by maintainers)

github_iconTop GitHub Comments

4reactions
madelsoncommented, May 2, 2017

@geleems I agree that the behavior with pooling represents the biggest problem here; that’s what burned us.

Maybe it’s a separate issue, but I do think that most callers to the API would expect the isolation level to reset on dispose despite the documentation that says otherwise. It seems weird that the recommended usage pattern would be to follow each transaction with another empty transaction just to get reasonable behavior. Much like the scoping of the foreach var (which changed in C#5), this seems like it could be one of those cases where despite the current behavior being intentional it is so confusing that it might be worth changing.

3reactions
nycdotnetcommented, Sep 13, 2019

This behavior is surprising and the sort of thing that is hard to notice in happy-path testing, but causes issues in prod. The way we’ve worked around it is to change the application name for any connections that opt-in to use snapshot isolation. This has the practical effect of ADO.NET creating two connection pools (my-service and my-service-snapshot), so when the isolation mode sticks to the connections in the snapshot pool it doesn’t hurt anything. It also helps with troubleshooting on the server-side because we can see which isolation mode the application was intending to use.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to prevent leak of transaction isolation level in pooled ...
I am using System.Data.SqlClient (4.6.1) in a dot net core 2.2 project. SqlClient maintains a pool of connections, and it has been reported...
Read more >
Plugging isolation level leaks in SQL Server
As a quick refersher, the isolation level of a transaction defines how the database handles locking and concurrency. A lower level provides ...
Read more >
SET TRANSACTION ISOLATION LEVEL (Transact-SQL)
A transaction cannot be set to SNAPSHOT isolation level that started with another isolation level; doing so will cause the transaction to abort....
Read more >
Transactions in .NET: From Basics to Best Practices
This isolation level provides a snapshot of the data at the start of a transaction, allowing for consistent reads without acquiring locks. It ......
Read more >
Things I've learned about SQL Server the hard way - PJSen Blog
The isolation level is an attribute of a connection between a client and the database server. A connection is called session in SQL...
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