LINQ + TransactionScope will not change isolation level in SQL Server Profiler - linq-to-sql

I'm using the following format for commiting changes to my db using linq.
Begin Transaction (Scope Serialized, Required)
Check Business Rule 1...N
MyDataContext.SubmitChanges()
Save Changes Done In Previous Query To Log File
End Transaction Scope
But in the SQL Server profiler I see the following line in the Connection:Start.
set transaction isolation level read committed
I went through this (http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/93a45026-0425-4d49-a4ac-1b882e90e6d5) and thought I had an answer;
Until I saw this (https://connect.microsoft.com/VisualStudio/feedback/details/565441/transactionscope-linq-to-sql?wa=wsignin1.0) on Microsoft Connect.
Can someone please tell me whether my code is actually executed under Serialized Isolation Level or whether it is infact just running under read committed?

It depends on how you created the transaction.
If you executed inline SQL to begin it (EG. BEGIN TRAN), L2S will not be aware of the transaction and will spin up a new nested one in READ COMMITTED.
However, if you used System.Transaction, or have a transaction set on your DataContext, SubmitChanges will participate in that transaction.
You can see these transaction starting and stopping in Profiler if you choose the TM: Begin Tran and TM: Commit Tran event classes.
Note: ADO.Net does not issue BEGIN TRAN nor does it issue SET TRANSACTION ISOLATION in batches, this is done at a lower level.
If you really want to confirm the behavior, create a trigger on a table that inserts the current isolation level into a logging table and check on it.
You can pick up your current isolation level by running:
SELECT CASE transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'Read Uncommitted'
WHEN 2 THEN 'Read Committed'
WHEN 3 THEN 'Repeatable Read'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL
FROM sys.dm_exec_sessions
where session_id = ##SPID

My guess is you created the DataContext, then used the TransactionScope. You have to open the connection inside the TransactionScope in order for it to enlist.

From http://entityframework.codeplex.com/workitem/1712
TransactionScope uses remote API calls rather than SQL commands to perform transactions in SQL Server. Those API calls are not included in the a standard trace in SQL Profiler.
You can include them by going to the "Event Selection" page, clicking on the "Show all events" checkbox and the selecting all the events from the Transactions category. This will allow you to see when such events as 'TM: Begin Tran Starting', 'SQLTransaction' and 'TM: Begin Tran Completed' actually occur.
You can also check the TransactionID column for the TSQL events in the "Event Selection" page to see the to which transaction each SQL batch being executed is associated.
Unfortunately I don't know of a direct way to observe the effective isolation level under which each command is being executed in SQL Profiler. But there is an indirect way...
When a connection is opened you will see an 'Audit Login' event in the trace. In many cases this event will contain the isolation level. Now, the 'Audit Login' happens before the actual isolation level is set, so the reported isolation level won't accurately reflect the isolation level of the transaction that is about to start. Here are some tips on how to interpret it:
When a connection opening actually hits a new connection it will always report the default transaction isolation level, e.g. you will see 'set transaction isolation level read uncommitted' (as I said, this is unrelated to the effective isolation level of your transaction as that one will be set at a later point)
After a connection has been opened and then returned to the connection pool (i.e. closed), subsequent connection openings will actually reuse that existing connection from the pool. In this case the 'Audit Login' will report the isolation level that was set when the connection got returned to the pool the last time. This can help you see the isolation level that was used, after the fact.
E.g. in your code snippet, the connection is open for a last time to roll back the transaction (because you have not marked the transaction as completed explicitly). In that 'Audit Login' event you should be able to see the isolation level that was effective when the connection was previously used to execute the query, represented by the line 'set transaction isolation level read uncommitted'.

Related

Should mysql transaction isolation level set to "read commited"?

After my airflow upgraded to 2.0.0(and then 2.0.1) and scheduler expanded to 3 nodes, something weird happened:
dagruns were success but the task instances were not scheduled at all
task failed with a null hostname(https://github.com/apache/airflow/issues/13692)
Task is set "upstream_failed" while upstream tasks are success(https://github.com/apache/airflow/issues/13671)
These phenomena never happened when there was only one scheduler node.
And I found that after task instances of a new dagrun were created by a scheduler node, they were not found in another scheduler node's task_instance_scheduling_decisions function.
Then I checked the mysql configurations and found transaction isolation was set to be Repeatable read by default.
After I set transaction isolation to be read commited, everything seems to be good now. But I still wonder are there any side effects?
Yes, READ COMMITTED is different than REPEATABLE READ.
If you use REPEATABLE READ, then in this transaction:
START TRANSACTION;
SELECT * FROM mytable;
SELECT * FROM mytable; -- i.e. the same query
COMMIT;
You are guaranteed that both SELECTs return the same result (as long as they are not locking queries).
But in READ COMMITTED, if some other session has committed a change to data in between the two SELECTs, they can return different results.
In other words, REPEATABLE READ means your SELECT queries always return data that was committed at the moment your START TRANSACTION started. Whereas READ COMMITTED means your SELECT queries return data that was committed after your transaction started, up until the time each respective SELECT starts.
Both levels of transaction isolation have proper uses. But they do behave differently.

MySQL not showing updated data even after commit

I am using two windows as I want to implement concept of transaction.
Window1: begin;
Window1: update employee set salary = 45000 where ssn = '123456789';
Window2: begin;
Window2: select * from employee where ssn = '123456789';
Here, this command shows me previous data which is correct.
Window1: commit;
Window2: select * from employee where ssn = '123456789';
Here, I should get the updated salary of 45000. But my window 2 is showing previous data only. Where am I doing the mistake?
You expectations are incorrect, that's all. What transactions see from each other's work is determined by the so called transaction isolation levels. By default, mysql uses repeatable read isolation level, which means:
If the transaction isolation level is REPEATABLE READ (the default
level), all consistent reads within the same transaction read the
snapshot established by the first such read in that transaction. You
can get a fresher snapshot for your queries by committing the current
transaction and after that issuing new queries.
You can change the isolation level to read committed to enable the behaviour you expect:
With READ COMMITTED isolation level, each consistent read within a transaction sets and reads its own fresh snapshot.

What transactions does commit / rollback affect?

Does it only affect whatever commands were after the relevant BEGIN transaction?
For example:
BEGIN TRAN
UPDATE orders SET orderdate = '01-08-2013' WHERE orderno > '999'
Now, assume someone else performs a data import that inserts 10,000 new records into another table.
If I subsequently issue a ROLLBACK command, do those records get discarded or is it just the command above that gets rolled back?
Sorry if this a stupid question, I'm only just starting to use COMMIT and ROLLBACK.
Any transaction is confined to the connection it was opened on.
One of the four ACID properties of any relational database management system is Isolation. That means your actions are isolated from other connections and vice versa until you commit. Any change you do is invisible to other connections and if you roll it back they will never know it happened. That means in turn that changes that happened somewhere else are invisible to you until they are committed. Particularly that means that you can't ROLLBACK anyone else's changes.
The Isolation is achieved in one of two ways. One way is to "lock" the resource (e.g. the row). If that happens any other connection trying to read from that row has to wait until you finish your transaction.
The other way is to create a copy of the row that contains the old values. In this case all other connections will see the old version until you commit your transaction.
SQL Server can use both isolation methods. Which one is used depends on the isolation level you choose. The two Snapshot Isolation Levels provide the "copy method" the other four use the "lock method". The default isolation level of "read committed" is one of the "lock method" isolation levels.
Be aware however that the isolation level "READ UNCOMMITTED" basically circumvents these mechanisms and allows you to read changes that others started and have not yet committed. This is a special isolation level that can be helpful when diagnosing a problem but should be avoided in production code.

Should I commit after a single select

I am working with MySQL 5.0 from python using the MySQLdb module.
Consider a simple function to load and return the contents of an entire database table:
def load_items(connection):
cursor = connection.cursor()
cursor.execute("SELECT * FROM MyTable")
return cursor.fetchall()
This query is intended to be a simple data load and not have any transactional behaviour beyond that single SELECT statement.
After this query is run, it may be some time before the same connection is used again to perform other tasks, though other connections can still be operating on the database in the mean time.
Should I be calling connection.commit() soon after the cursor.execute(...) call to ensure that the operation hasn't left an unfinished transaction on the connection?
There are thwo things you need to take into account:
the isolation level in effect
what kind of state you want to "see" in your transaction
The default isolation level in MySQL is REPEATABLE READ which means that if you run a SELECT twice inside a transaction you will see exactly the same data even if other transactions have committed changes.
Most of the time people expect to see committed changes when running the second select statement - which is the behaviour of the READ COMMITTED isolation level.
If you did not change the default level in MySQL and you do expect to see changes in the database if you run a SELECT twice in the same transaction - then you can't do it in the "same" transaction and you need to commit your first SELECT statement.
If you actually want to see a consistent state of the data in your transaction then you should not commit apparently.
then after several minutes, the first process carries out an operation which is transactional and attempts to commit. Would this commit fail?
That totally depends on your definition of "is transactional". Anything you do in a relational database "is transactional" (That's not entirely true for MySQL actually, but for the sake of argumentation you can assume this if you are only using InnoDB as your storage engine).
If that "first process" only selects data (i.e. a "read only transaction"), then of course the commit will work. If it tried to modify data that another transaction has already committed and you are running with REPEATABLE READ you probably get an error (after waiting until any locks have been released). I'm not 100% about MySQL's behaviour in that case.
You should really try this manually with two different sessions using your favorite SQL client to understand the behaviour. Do change your isolation level as well to see the effects of the different levels too.

How the transaction isolation levels in ssis works?

I have few questions about ssis transction isolation levels.
consider a scenario:I have an Execute SQL task which insert a data in a table A.This task is pointing to a dataflow task,which read the data which is previously inserted on A.I have started Distributed transaction and if i set transaction isolation in ssis as readcommited,whether it commit the table A at first execute sql task and move to dataflow task?
Also what about other isolation level in this scenario?
From what I can understand from your question you're asking what's the appropriate transaction isolation if you want to read data from a table in the same transaction that data is being written to the table? As far as I know, it shouldn't matter. The isolation types only address situations where another transaction wants to modify the same rows that the uncommitted transaction is modifying. In other words just reading the table should have no problems and you should see the data from the first Execute SQL task. Data written in a transaction is available before the transaction is committed.
For further reading, this is from the Oracle docs, but the same definition should apply to SQL and SSIS packages. Notice they address when two transactions want to modify the same data:
SERIALIZABLE: If a serializable transaction tries to execute a SQL data manipulation statement that modifies any table already modified by an uncommitted transaction, the statement fails.
READ COMMITTED: If a transaction includes SQL data manipulation statements that require row locks held by another transaction, the statement waits until the row locks are released.
DO NOT DOWNVOTE THIS ANSWER. I got it from MSDN forums and I am keeping it here for reference.
http://social.msdn.microsoft.com/Forums/en-US/3dcea5f6-32ef-40aa-90d5-0f2fef9e1d38/isolation-level-in-ssis
A few observations...
The IsolationLevel property in SSIS components only applies when distributed transactions are used (package or other container has TransactionOption=Required). So in that regard, Isolation Level is a bit misleading in SSIS. Even if you set it, its not going to help unless a transaction is opened by SSIS. I wrote about that limitation here: http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.dts.runtime.dtscontainer.isolationlevel.aspx
If you are customizing the isolation level in TSQL (stored procedure or just at the beginning of the a batch) which is called from SSIS, you can override the default SQL Server isolation level Read_committed, however if you just point to a table name in a dataflow source or destination, you can't set the isolation level.
If you choose to manually set the isolation level in other ways in each of your queries, there are a few techniques:
1. If you were to run the SET options in your Commands "set transaction isolation level read uncommitted" http://msdn.microsoft.com/en-us/library/ms173763.aspx
Be careful with Read Uncommitted & Nolock, since it can read dirty data (data changes in flux not fully committed by other connections.)
Using Locking Hints such as http://technet.microsoft.com/en-us/library/ms187373.aspx
select * from t1 (nolock)
Setting the auto-commit isolation level in OLEDB or ODBC if there is a place to override that in the connection string or driver properties of your driver http://msdn.microsoft.com/en-us/library/ms175909.aspx I haven't tested that, but it may be possible.
To see the isolation level being used, if your RDBMS that you connect to is SQL Server 2005/2008, while the connection/session is still active you can query DBCC USEROPTIONS or selecting from dm_exec_sessions
select transaction_isolation_level,* from sys.dm_exec_sessions
(0 = Unspecified, 1 = ReadUncomitted, 2 = ReadCommitted, 3 = Repeatable, 4 = Serializable, 5 = Snapshot)
We also found out that Snapshot Isolation Level is incompatible with Distributed Transactions, therefore it is not possible to use Snapshot Isolation Level through the SSIS properties. A workaround for that would be to use the TSQL syntax for Snapshot Isolation within your Data Sources & ExecuteSqlTask commands directly.
Best of luck, Jason
His MSDN Profile - http://social.msdn.microsoft.com/profile/jason%20h%20(hdinsight)/?ws=usercard-mini