SET TRANSACTION ISOLATION LEVEL works only with transactions? - c#

In the official example here we have the SET TRANSACTION ISOLATION LEVEL being used in conjunction with an explicitly defined transaction.
My question is, if I execute a query from a SqlCommand, like:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * from MyTable
would I benefit from the new isolation level I set?
Or do I need to explicitly define a transaction like this?
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRANSACTION;
SELECT * from MyTable
COMMIT TRANSACTION;
UPDATE:
As per Randy Levy's answer, I will update my query as follows:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * from MyTable;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
This is to overcome possible isolation level leaks when using pooling.

Yes, you would benefit from the transaction isolation level that you set even if not within an explicit BEGIN TRANSACTION. When you set the transaction isolation level it is set on a connection level.
From SET TRANSACTION ISOLATION LEVEL (Transact-SQL):
Only one of the isolation level options can be set at a time, and it
remains set for that connection until it is explicitly changed.
One "gotcha" (issue) that can occur is that the isolation level can leak between different connections when using pooling. If you are explicitly setting an isolation level in one (or some) particular piece(s) of code (but using the default most other places) and also using connection pooling. This can cause strange issues if code expects the default isolation level "A" but obtains a connection that had the isolation level explicitly set to "B".
It seems this issue is now fixed in later versions of SQL Server: SQL Server: Isolation level leaks across pooled connections

The first one
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * from MyTable
will work. The transaction level you set applies to each subsequent transaction, and your SELECT statement is its own implicit transaction.
You would only need to explicitly start a transaction if you needed to ensure some degree of consistency throughout multiple reads. For example if you use SERIALIZABLE then you could wrap multiple SELECTs in a transaction and ensure that the underlying data isn't modified while you're reading it.

Every statement in SQL Server is run in the context of a transaction. When you do something like
select * from [dbo].[foobar];
SQL Server really does:
begin transaction;
select * from [dbo].[foobar];
commit;
So, setting an explicit transaction isolation level does affect transactions. Even the implicit ones that the database engine starts on your behalf!

Related

Read committed Isolation Level in postgres

I tried to insert and read the values from same table using readcommitted isolation level with in the same transaction. https://www.postgresql.org/docs/9.5/transaction-iso.html from this document I came to know read comitted isolation level will read the uncommitted changes with in the same transaction. But I am not able to read the uncommitted values. Please correct me if my understanding is wrong!
In Postgresql, in open transactions, you can read any value inserted/updated by the same transaction. transaction isolation is a construct that defines the isolation at the transaction level inside the transaction stored procedure can read any value it inserted/updated even if it is not committed and regardless of isolation level.

Isolation level in C# or SQL - which one will be used?

I have set isolation level in C# code as readcommitted, and I am calling a stored procedure which is timing out due to some reason. The stored procedure does not have any set isolation level statement.
In SQL Server, database level isolation level is read committed snapshot.
So which isolation level will be used? The one defined in SQL Server, or the one set from C#?
There is no such thing as a 'database isolation level'. What you describe is a database options, called READ_COMMITTED_SNAPSHOT:
READ_COMMITTED_SNAPSHOT { ON | OFF } ON Enables Read-Committed Snapshot option at the database level. When it's enabled, DML statements start generating row versions even when no transaction uses Snapshot Isolation. Once this option is enabled, the transactions specifying the read committed isolation level use row versioning instead of locking.
So when READ_COMMITTED_SNAPSHOT is ON a transaction that specified read committed isolation level will instead see a snapshot isolation level.
It is important to understand that there is another database option: ALLOW_SNAPSHOT_ISOLATION that also must be set to ON for Snapshot isolation to occur. See Snapshot Isolation in SQL Server.
When in doubt, you can always check sys.dm_tran_current_transaction which has a column named transaction_is_snapshot:
Snapshot isolation state. This value is 1 if the transaction is started under snapshot isolation. Otherwise, the value is 0.
Also, there are subtle differences between true snapshot isolation level and read committed isolation that is changed to snapshot by READ_COMMITTED_SNAPSHOT.
Commands to set the transaction isolation level are processed in order received. So the last one wins. On SQL Server, you can set the default transaction isolation level, but is just a default.

SQL Server management hangs when I have snapshot isolation in code

I have set my database snapshot_isolation_state_desc = ON
In c# when I start a new transaction
var dbTransaction = _myContext.Database.BeginTransaction(IsolationLevel.Snapshot);
// delete
--- break point
//insert
on the break point when I go to sql management studio and query a table it hangs until i complete the transaction. I would like to be able to see the data in the table not just hang.. But I also want to complete my c# transaction. Am I using the wrong Isolation level?
Thanks in advance
Am I using the wrong Isolation level?
Yes. The default isolation level in SSMS is READ_COMMITTED so writers (the app code) will block readers (SSMS query) unless you've turned on the READ_COMMITTED_SNAPSHOT database option. Each session can run in different isolation level and the behavior of each will depend on the chosen level of that session.
Set the desired isolation level in the SSMS query window prior to querying the table so that your query is not blocked by the uncommitted change made by the app code:
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;

Allow select while transation is running

Here is the code to modify table from in one transatcion. As I know why IsolationLevel Serializable the read is not blocked, but I can't select records from the table. How can I run transaction while not blocking selects from the table ?
TransactionOptions opt = new TransactionOptions();
opt.IsolationLevel = IsolationLevel.Serializable;
using (TransactionScope scope = new TransactionScope(
TransactionScopeOption.Required, opt))
{
// inserts record into table
myObj.MyAction();
// trying to select the table from Management Studio
myObj2.MyAction();
scope.Complete();
}
Have a look at http://msdn.microsoft.com/en-us/library/ms173763.aspx for an explanation of the isolation levels in SQL Server. SERIALIZABLE offers the highest level of isolation and takes range locks on tables which are held until the transaction completes. You'll have to use a lower isolation level to allow concurrent reads during your transaction.
It doesn't matter what isolation level your (insert, update, etc) code is running under - it matters what isolation level the SELECT is running under.
By default, this is READ COMMITTED - so your SELECT query is unable to proceed whilst there is *un*committed data in the table. You can change the isolation level that the select is running under using SET TRANSACTION ISOLATION LEVEL to allow it to READ UNCOMMITTED. Or specify a table hint (NOLOCK).
But whatever you do, it has to be done to the connection/session where the select is running. There's no way for you to tell SQL Server "Please, ignore the settings that other connections have set, just break their expectations".
If you generally want selects to be able to proceed on a database wide basis, you might look into turning on READ_COMMITTED_SNAPSHOT. This is a global change to the database - not something that can or should be toggled on or off for the running of a single statement or set of statements, but it then allow READ COMMITTED queries to continue, without requiring locks.
Serializable is the highest transaction level. It will hold the most restricted locks.
What are you trying to protect with an isolation level of Serializable.
Read Commited Snapshot might be more appropriate, but we would need more information to be sure.

.NET transaction management without TransactionScope

I was actively using TransactionScope in my application and was happy. But now I came to the situation where TransactionScope is not enough flexible: first of all, because I can't change IsolationLevel dynamically.
What is the easiest way to replace TransactionScope by database transaction which can be managed manually? One of the features I want to keep is the support of cross-connections transactions.
I think that the conculsion is that you cannot do this: Have both a distributed transaction and change the isolation level.
You cannot change the isolation level of a transaction after it has started.
To use cross connection transactons you need to use transaction scope, or a COM+ transaction via enterprise services. In both cases you cannot change the isolation level after the transaction is created.
It is possible to to change the isolation level of a SQL connection using the "set transaction isolation level " SQL statement.

Categories