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.

ExecuteScalar does not always raise an exception when selected as deadlock victim

See original GitHub issue

Describe the bug

We have encountered an issue in production where ExecuteScalar run in context of a RepeatableRead transaction intermittently fails to raise an exception when SQL Server selects it as a deadlock victim and rolls back the transaction. The transaction state is correctly set to Aborted, but the lack of an exception confuses application code and libraries like EF Core and who assume (fairly reasonably) that no exception means success.

Additionally, ExecuteScalar is returning the value that would be expected for a successful transaction even though the transaction has been rolled back.

The issue does not seem to occur when using ExecuteReader or ExecuteNonQuery.

I have a reduced repro case which consistently reproduces the error on SQL Server 12 and 13, tested across multiple machines. The issue reproduces with System.Data.SqlClient/dotnet core 2.1 and Microsoft.Data.SqlClient/dotnet core 3.1.

To reproduce

  1. Clone the repository https://github.com/deadalusai/SqlClient-Aborted-Transaction-Repro

  2. Create a new database using the ZombieDb.sql script

  3. Run the test program:

    For .NET Core 3.1 with Microsoft.Data.SqlClient:

    > dotnet run -p .\ZombieTester.NET31.csproj
    

    For .NET Core 2.1 with System.Data.SqlClient:

    > dotnet run -p .\ZombieTester.NET21.csproj
    
  4. Press any key to start testing for the error case. The test will run until it reproduces the issue or times out.

Expected behavior

A SqlException to be raised when a command is selected as a deadlock victim.

Further technical details

Microsoft.Data.SqlClient version: 1.1.1 System.Data.SqlClient version: 4.8.1 .NET target: .NET Core 3.1, .NET Core 2.1 SQL Server version: SQL Server 2017, SQL Server 2016 Operating system: Windows 10

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:1
  • Comments:13 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
vonzshikcommented, Aug 3, 2021

Hello! Tested @deadalusai’s example with SqlClient 3.0, the problem is still reproducible. Did a small research, and it looks like SqlClient reports the error depending on when exactly that error is read - either on SqlDataReader.Read (then TdsParser.TryRun is called with RunBehavior.ReturnImmediately) or on SqlDataReader.Close (then TdsParser.TryRun is called with RunBehavior.Clean, which prevents TdsParser.TryRun from throwing that error).

1reaction
deadalusaicommented, May 18, 2021

We’ve had some success with prepending something like the following before every insert/update/delete SQL operation:

IF (@@TRANCOUNT = 0) THROW 51000, 'Not running in a transaction.', 1;

For SqlClient you just prepend it to the command text. For EF Core 3.0 you can use interceptors: https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.x/#interception-of-database-operations

Read more comments on GitHub >

github_iconTop Results From Across the Web

ADO.NET ExecuteScalar() not throwing exception
This means when the exception is raised after a result is returned you will never see it with the ExecuteScalar() method, as the...
Read more >
Select from db with transaction - MSDN - Microsoft
Transaction (Process ID 71) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction....
Read more >
Error Handling in SQL 2000 – a Background
Being selected as a deadlock victim. Permission denied to table or stored procedure. ROLLBACK or COMMIT without any active transaction.
Read more >
Error and Transaction Handling in SQL Server Part Three
The error could be due to a bug in your code, incorrect data from a caller you had reason to trust, or it...
Read more >
【转贴】Error Handling in SQL Server - N/A2011
There is no way to prevent SQL Server from raising error messages. There is a small set of ... Being selected as a...
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