Sql Server 2014 sp_reset_connection behavior inside transaction - sql

What is the behavior of sp_reset_connection when it is run inside a transaction? I am looking for clarification so I can decide if I need to restructure my code, or if I can leave it as is.
I have a c# application that uses an ORM(Petapoco) that doesn't seem to respect the ambient transaction(System.Transactions.TransactionScope). I can see the transaction beginning in Sql Profiler, but before every call in the transaction the ORM is sending a sp_reset_connection call. I am also seeing the Transaction Commit event in Sql Profiler when my ambient transaction is completed.
I have seen other questions on StackOverflow that suggest the Transaction Isolation scope is reset when sp_reset_connection is called (see: What does “exec sp_reset_connection” mean in Sql Server Profiler?), but I can't find any info on what happens specifically when sp_reset_connection is called inside of a transaction.

The sp_reset_connection stored procedure is not well documented since it's an internal stored procedure and never called directly. Be aware that it may change or be removed in the future without notice. That being said, it is useful to know a little about the internals for troubleshooting and correlating activity trace data.
The purpose of the proc is to restore connection environment state to that of a newly opened connection to support connection pooling. The client API specifies whether a connection is to be reset by setting either the RESETCONNECTION or RESETCONNECTIONSKIPTRAN bits of the TDS protocol status field when a request is issued on a newly reused connection from the pool. SQL Server internally invokes the sp_reset_connection RPC you see in a trace when either of those flags are set.
The TDS protocol documentation desribes these flags so we can infer this is what sp_reset_connection does under the covers. Below is the an excerpt from the documentation:
RESETCONNECTION (Introduced in TDS 7.1) (From client to server) Reset
this connection before processing event. Only set for event types
Batch, RPC, or Transaction Manager request. If clients want to set
this bit, it MUST be part of the first packet of the message. This
signals the server to clean up the environment state of the connection
back to the default environment setting, effectively simulating a
logout and a subsequent login, and provides server support for
connection pooling. This bit SHOULD be ignored if it is set in a
packet that is not the first packet of the message.
This status bit MUST NOT be set in conjunction with the
RESETCONNECTIONSKIPTRAN bit. Distributed transactions and isolation
levels will not be reset. 0x10
RESETCONNECTIONSKIPTRAN (Introduced in TDS 7.3) (From client to
server) Reset the connection before processing event but do not modify
the transaction state (the state will remain the same before and after
the reset). The transaction in the session can be a local transaction
that is started from the session or it can be a distributed
transaction in which the session is enlisted. This status bit MUST NOT
be set in conjunction with the RESETCONNECTION bit. Otherwise
identical to RESETCONNECTION.
The low-level client API (SqlClient here) indirectly controls the behavior of sp_reset_connection by setting those flags as needed. When a connection is reused outside a TransactionScope, the RESETCONNECTION flag is set as can be seen in this network packet trace (Wireshark):
Below is a trace of the first request issued on a reused connection from within the scope of a TransactionScope using block:
As you can see, the reset within TransactionScope will not rollback the transaction. Consequently, even if your ORM follows an open/execute/close pattern for data access, your outer TransactionScope transaction context will be honored. The transction will be committed as long as you invoke TransactionScope.Complete before exiting the transaction scope. You can include a TM Commit Tran completed event to your Profiler trace to see the commit when the TransactionScope exits.
BTW, Profiler/SQL trace is deprecated. Use Extended Events instead going forward. Also, as suggested in the other answer, be sure to specify the desired transaction isolation level (e.g. read committed) when you use TransactionScope. The default is serializable which can have side effects like unnecessary blocking and deadlocks. I suggest you use serializable only if you specifically need that strict level of isolation.

Related

Can a SQL Server connection be reused on two different concurrent requests?

Our setup is ASP.NET MVC using Ninject and we instantiate and open a new connection on a per request basis using the same connection string every time. Based on this MSDN article Connection Pooling will reuse connections, but I am wondering if it's possible for a connection in used on one request to be reused on a concurrent request at the same exact time.
The reason for this question is we have a query where we set the ISOLATION LEVEL to READ UNCOMMITTED run the query and then set it back to what it was. Since setting the ISOLATION LEVEL is at the connection level we are wondering if it's possible for other requests to be reading "dirty" data during the time frame when the ISOLATION was READ UNCOMMITTED.
Whenever a connection is placed back into the pool, it is reset via a call to sp_reset_connection. Unfortunately, it does NOT affect the isolation level.
There are complaints about this behavior here:
https://connect.microsoft.com/SQLServer/feedback/details/243527/sp-reset-connection-doesnt-reset-isolation-level
If you must change the isolation level, I'm afraid you'll need to:
Explicitly set isolation level on every query
Use a different connection string (preferably with pooling disabled) when changing isolation level
Move isolation level changes into stored procedures

Using transactions with EF4.1 and SQL 2012 - why is DTC required?

I've been doing a lot of reading on this one, and some of the documentation doesn't seem to relate to reality. Some of the potential causes would be appropriate here, however they're only related to 2008 or earlier.
I define a transaction scope. I use a number of different EF contexts (in different method calls) within the transaction scope, however all but one of them are only for data reads. The final use of a Context is to create and add some new objects to the context, and then call
context.SaveChanges()
IIS is running on one server. The DB (Sql2012) is running on another server (WinServer 2012).
When I execute this code, I receive the error:
Network access for Distributed Transaction Manager (MSDTC) has been
disabled. Please enable DTC for network access in the security
configuration for MSDTC using the Component Services Administrative
tool.
Obviously, if I enable DTC on the IIS machine, this goes away. However why should I need to?
This:
http://msdn.microsoft.com/en-us/library/ms229978.aspx
states:
• At least one durable resource that does not support single-phase
notifications is enlisted in the transaction. • At least two durable
resources that support single-phase notifications are enlisted in the
transaction
Which I understand is not the case here.
Ok. I'm not entirely sure if this should have been happening (according to the MS doco), but I have figured out why and the solution.
I'm using the ASPNet membership provider, and have two connection strings in my web.config. I thought the fact that they were pointing to the same DB was enough for them to be considered the same "durable resource".
However I found that the membership connection string also had:
Connection Timeout=60;App=EntityFramework
whereas the Entity Framework connection string didn't.
Setting these values to the same connection string meant that the transaction is not escalated to MSDTC.

How can I use Transactional scope in SSIS using MS Access databases?

Using MS Access DB is nearly always a pain. What really hurts is that you can't even use a distributed transaction in SSIS when utilizing an OLE-DB Connection accessing an MS Access file. EVEN IF YOU ONLY INTEND TO READ IT! WTF? What kind of transaction support is that? So can anybody tell me how to make a SSIS package transactional in this case? Using the normal Transaction mode results in a The Acquire Connection manager failed with error code 0xC0202009
I've run into scenarios like this (ancient MySQL instance and a DB2 where they denied us create transaction rights) and what I found to be an effective solution is to cache the source that doesn't support transactions in a raw file, cache connection manager, or a recordset destination. Raw file would be my "go to" for sheer simplicity sake but the others may be needed based on component requirements.
General appearance of a package would look like: Package (or enclosing container) with transaction set to Required. This will create a transaction that contained tasks can enlist in. I then create a "starter" container that explicitly opts out of a transaction (transaction option: notsupported). That's where we will want to access the resource that doesn't support transactions. The default transaction option, Supported, means it will enlist in an open transaction if one is available. I put all the tasks that need the transaction in the supported container.
In the dataflow that is outside the transaction, I dump to a RAW file. I use the same query that I'd use in a "normal" transaction supported source.
In the data flow that consumes the cache output, I use the file generated in the first step and voila, transactions working as intended for the destination and no transaction attempted on the source that didn't support it.
You can set the RetainSameConnection property on the OLE DB Connection Manager to True, e.g. when writing to a SQL Server as seen here. This in return enables you to write a BEGIN TRANSACTION in one Execute SQL Task and then choose to COMMIT or ROLLBACK in another one.
But Beware: Avoid loose ends as this will create multiple connections when running tasks parallel. You have to create a chain from BEGIN TRAN to COMMIT, otherwise it will fail.
See http://www.morrenth.com/transaction-and-retainsameconnection-in-ssis-ole-db-connection-manager.aspx

Using IsolationLevel.Snapshot but DB is still locking

I'm part of a team building an ADO.NET based web-site. We sometimes have several developers and an automated testing tool working simultaneously a development copy of the database.
We use snapshot isolation level, which, to the best of my knowledge, uses optimistic concurrency: rather than locking, it hopes for the best and throws an exception if you try to commit a transaction if the affected rows have been altered by another party during the transaction.
To use snapshot isolation level we use:
ALTER DATABASE <database name>
SET ALLOW_SNAPSHOT_ISOLATION ON;
and in C#:
Transaction = SqlConnection.BeginTransaction(IsolationLevel.Snapshot);
Note that IsolationLevel Snapshot isn't the same as ReadCommitted Snapshot, which we've also tried, but are not currently using.
When one of the developers enters debug mode and pauses the .NET app, they will hold a connection with an active transaction while debugging. Now, I'd expect this not to be a problem - after all, all transactions are using snapshot isolation level, so while one transaction is paused, other transactions should be able to proceed normally since the paused transaction isn't holding any locks. Of course, when the paused transaction completes, it is likely to detect a conflict; but that's acceptable so long as other developers and the automated tests can proceed unhindered.
However, in practice, when one person halts a transaction while debugging, all other DB users attempting to access the same rows are blocked despite using snapshot isolation level.
Does anybody know why this occurs, and/or how I can achieve true optimistic (non-blocking) concurrency?
The resolution (an unfortunate one for me): Remus Rusanu noted that writers always block other writers; this is backed up by MSDN - it doesn't quite come out and say so, but only ever mentions avoiding reader-writer locks. In short, the behavior I want isn't implemented in SQL Server.
SNAPSHOT isolation level affects, like all isolation levels, only reads. Writes are still blocking each other. If you believe that what you see are read blocks, then you should investigate further and check out the resource types and resource names on which blocking occurs (wait_type and wait_resource in sys.dm_exec_requests).
I wouldn't advise in making code changes in order to support a scenario that involves developers staring at debugger for minutes on end. If you believe that this scenario can repeat in production (ie. client hangs) then is a different story. To achieve what you want you must minimize writes and perform all writes at the end of transaction, in one single call that commits before return. This way no client can hold X locks for a long time (cannot hang while holding X locks). In practice this is pretty hard to pull off and requires a lot of discipline on the part of developers in how they write the data access code.
Have you looked at the locks when one developer pauses the transaction? Also, just turning on snapshot isolation level does not have much effect. Have you set ALLOW_SNAPSHOT_ISOLATION ON?
Here are the steps:
ALTER DATABASE <databasename>
SET READ_COMMITTED_SNAPSHOT ON;
GO
ALTER DATABASE <database name>
SET ALLOW_SNAPSHOT_ISOLATION ON;
GO
After the database has been enabled for snapshot isolation, developers and users must then request that their transactions be run in this snapshot mode. This must be done before starting a transaction, either by a client-side directive on the ADO.NET transaction object or within their Transact-SQL query by using the following statement:
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
Raj

What does sp_reset_connection do?

sp_reset_connection seems to be called by SQL Server connection pooling, to ensure that connections reused from the pool have most of their settings reset. Does anyone know exactly what it does and doesn't do though?
eg I see from this post that it doesn't reset the transaction isolation level
Data access API's layers like ODBC, OLE-DB and SqlClient call the (internal) stored procedure sp_reset_connection when re-using a connection from a connection pool. It does this to reset the state of the connection before it gets re-used.
There does not appear to be official documentation on what things get reset, but here is an unofficial list.
sp_reset_connection resets the following aspects of a connection:
It resets all error states and numbers (like ##error)
It stops all EC's (execution contexts) that are child threads of a
parent EC executing a parallel query
It will wait for any outstanding I/O operations that is outstanding
It will free any held buffers on the server by the connection
It will unlock any buffer resources that are used by the connection
It will release all memory allocated owned by the connection
It will clear any work or temporary tables that are created by the
connection
It will kill all global cursors owned by the connection
It will close any open SQL-XML handles that are open
It will delete any open SQL-XML related work tables
It will close all system tables
It will close all user tables
It will drop all temporary objects
It will abort open transactions
It will defect from a distributed transaction when enlisted
It will decrement the reference count for users in current database;
which release shared database lock
It will free acquired locks
It will releases any handles that may have been acquired
It will reset all SET options to the default values
It will reset the ##rowcount value
It will reset the ##identity value
It will reset any session level trace options using dbcc traceon()
sp_reset_connection will NOT reset:
Security context, which is why connection pooling matches connections
based on the exact connection string
If you entered an application role using sp_setapprole, since application
roles can not be reverted
The transaction isolation level
From this forum post:
The sp_reset_connection stored procedure is used to reset a connection
so that when it is used in a pool, nothing from a previous session is stored
that is connection-specific.