From comments, I'm guessing you had a client side Command timeout that has aborted the SQL query. This does not rollback the transaction because the connection stays open on SQL Server due to connection pooling.

So, you need to use SET XACT_ABORT ON or add some client rollback code

See SQL Server Transaction Timeout for all the gory details

sleeping SPID blocking other transactions
Does Stack Overflow honor the Do not track header... or is support going to be added later? ...(it doesn't seem to honor the header at the moment).
