The syntax you are using is valid, all statements executed after the SET TRANSACTION ISOLATION LEVEL
command will use the specified isolation level.
Consider the following table:
CREATE TABLE dbo.test
(
ID int identity(1,1) Primary key
, Field nvarchar(10)
)
GO
INSERT INTO dbo.test(Field)
Values ('XXXXXXXXXX')
GO 100
Next, start a transaction and execute 2 statements.
The first statement will use REPEATABLE READ
(which won't release its shared locks when the statement completes), the second statement will use SERIALIZABLE
(which will take and hold range locks)
BEGIN TRANSACTION
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
SELECT *
FROM dbo.test
WHERE id = 100
-- This will show a shared lock on key 100, the lock is kept during the transaction because repeatable read is used
SELECT *
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
-- Isolation level 3 = repeatable read
SELECT transaction_isolation_level
FROM sys.dm_exec_sessions
WHERE session_id = @@SPID
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
SELECT *
FROM dbo.test
WHERE id >= 0 and id < 10
-- This will show the previous shared lock on key 100 + additional RangeS-S key locks taken by the serializable statement
SELECT *
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
-- Isolation level 4 = Serializable
SELECT transaction_isolation_level
FROM sys.dm_exec_sessions
WHERE session_id = @@SPID
COMMIT TRANSACTION
Looking at the output of sys.dm_tran_locks
and sys.dm_exec_sessions
you can see that the two statements issue different locks and use different isolation levels within the same transaction.
Although it's technically possible, I tend to use a single isolation level within a transaction.
When combining SNAPSHOT
isolation with pessimistic locking you could get some unexpected results.
Imagine starting a transaction in SNAPSHOT
isolation and reading some data.
Next, a second session updates the data you just read.
The first transaction switches to READ COMMITTED
and reads the data again, SQL Server will now return the updated values.
Finally, you switch to SNAPSHOT
isolation again and read the data. You'll use the previously created snapshot to read from and the old values will be returned.
-- Note: you have to set your isolation level to snapshot before starting your transaction otherwise you will get an error
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
BEGIN TRANSACTION
-- Returns XXXXXXXXXX
SELECT *
FROM dbo.test
WHERE id = 1
-- Run "UPDATE dbo.test SET Field = 'YYYYYYYYYY' WHERE id = 1" in a separate session
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
-- Returns YYYYYYYYYY
SELECT *
FROM dbo.test
WHERE id = 1
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
-- Returns XXXXXXXXXX
SELECT *
FROM dbo.test
WHERE id = 1
COMMIT