These days I improved my knowledge about Isolation Level of transactions.
In particular, i had problem to understand well the difference between Read Committed and Repeatable Read.
I've read this fantastic article, and I understand all about dirty-reads, non-repeatable read and phantoms read but i don't understand what happen with multiple transactions in update.
Example:
Table: "Test" (Field: ID_REC - Data)
Transaction A:
set transaction isolation level read committed;
begin transaction
update test
set DATA = 't1'
where ID_REC = 1
waitfor delay '00:00:20'
commit transaction
Transaction B: (the same but with another record)
set transaction isolation level read committed;
begin transaction
update test
set DATA = 't2'
where ID_REC = 2
commit transaction
I execute both transactions in two seconds.
Second transaction doesn't start until first one is finished.
And also i can't execute query (select * from test).
So: why happen this? Transactions works on different rows... and about this case, what is the difference between Read Committed and Repeatable Read?
Related
I have read that serializable isolation level blocks only: insert, update, delete but NOT read.
I have run in one window:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE [dbo].[Categories]
SET name = 'aaa'
WHERE categoryid = 4;
-- without commit
And in the second window:
SELECT TOP (1000) [CategoryId]
,[Name]
FROM [dbo].[Categories]
And the above query is waiting for the end of the first query. So does serialization isolation level block also read?
Yes it blocks reads. Your transaction is not committed, so you can still do a rollback. That means the data you have updated should not be read by any other process before you commit.
"does serialization isolation level block also read" : No.
Serializable acquires some lock (in Ms Sql its shared lock + range lock) which prevents writes from other transactions.
Its the UPDATE statement's exclusive lock (the above shared lock now converts to exclusive lock) that prevents second transaction's SELECT (Read Commited or Repeatable Read by deafult depending on db) to wait.
What is the relation between isolation levels of relational databases and select for update?
If I use the plain vanilla JDBC connectivity with SQL Server and set isolation level to READ_REPEATABLE and use a simple select, would I see inconsistency in repeatable reads or not? Or should I use select for update always to avoid inconsistent repeatable reads in transactions? If so, what is the deal with isolation levels, how they would come into play?
SQL Server doesn't have the select ... for update syntax. The equivalent in SQL Server is to use the UPDLOCK table hint.
This hint is used when reading a row and immediately updating the same row in an atomic transaction. EG
declare #balance = (select balance from account where accountId = #id)
update account set balance = #balance + #amount where accountId = #id
At READ COMMITTED, or in any isolation level without a mult-statement transaction, multiple sessions can run the first query, and have lost updates when updating the balance.
Using the REPEATABLE READ or SERIALIZABLE isolation level will prevent this update anomaly, but they do it by blocking the first writer if there are any concurrent transactions that have read the row, and if one of the other transactions attempts to update the row, causing a deadlock.
Mostly this behavior is not worth the performance cost and annoyance of handling deadlocks. So you use 'select for update' aka UPDLOCK to place a U lock on the row while reading and block subsequent readers from acquiring a conflicting lock.
eg
declare #balance = (select balance from account with (updlock) where accountId = #id)
update account set balance = #balance + #amount where accountId = #id
Not exactly sure what you mean by "inconsistent repeatable reads" but with the REPEATABLE READ isolation level in SQL Server, shared locks will be held until the end of the transaction. Only committed data will be returned and other sessions cannot modify the rows read until the transaction is committed (or auto-committed in the case of no explict transaction).
REPEATABLE READ does not prevent other sessions from inserting new rows so rerunning the same query in the same transaction may return new rows (phantom reads) that were not returned originally.
The documentation describes this in more detail along with the other transaction isolation levels.
There is no need to intervene with the default behavior using hints or otherwise.
SQL Server guarantees transaction isolation levels per your declared required level.
REPEATABLE READ guarantees that within a transaction, your statements will see a consistent view of the data that was read, but doesn't guarantee there will be no phantom rows. To avoid the latter you will need to use SERIALIZABLE.
The higher the isolation, the higher the concurrency penalty of course.
See the JDBC Page for isolation levels and the general page for SET TRANSACTION ISOLATION LEVEL for a somewhat more in-depth discussion.
HTH
If I'm using
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Do I need to wrap the query in a transaction
e.g.
BEGIN TRAN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM
T1
COMMIT
Or can I just have a normal query?
Also, is there any benefit to including SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED and WITH (NOLOCK). I understand that one is for the table level and one is for the whole connection level. But is there any benefit to having both?
Such as:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM
T1 WITH (NOLOCK)
Always we executes procedure of INSERT, UPDATE and DELETE transaction with READ COMMITTED ISOLATION LEVEL. If we need dirty data from any table then it helps. Because Transaction is defined with READ COMMITTED and table return dirty reads using WITH(NOLOCK) in JOIN Query.
You don't need to wrap the query below in a transaction:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Because even if wrapping the query above in a transaction as shown below, isolation level is still set on session(connection) level but not on transaction level:
BEGIN TRAN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
COMMIT
So, even if rollbacking isolation level as shown below, isolation level is not rollbacked so it's still READ UNCOMMITTED but not READ COMMITTED.
BEGIN TRAN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
ROLLBACK -- Isolation level is still "READ UNCOMMITTED" but not "READ COMMITTED"
I am trying to update table, which controlls application (application performs some select statements). I would like to update the table in transaction with isolation level set to read uncommited, so if application doesn't work as expected I can rollback transactions.
But following code doesn't work:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
go
begin transaction
go
update [DB].[dbo].[Table]
set ID = ID - 281
where ID > 2
When I open another query window, I cannot query this table... I thought, that with such transaction level I would be able to query the table without rolling back/commiting transaction.
Isolation level works in another way as you suppose.
You can only read uncommitted data, but others still cannot see what you done within transaction until you commit.
If you want to see uncommitted data from this transaction in your select you need to set
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
to this select
You need to use SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED from a session which reads data.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT *
FROM [DB].[dbo].[Table]
This query will execute immediately without lock. And you'll see the dirty data.
I have the following SP:
CREATE PROCEDURE [dbo].[sp_LockReader]
AS
BEGIN
SET NOCOUNT ON;
begin try
set transaction isolation level serializable
begin tran
select * from teste
commit tran
end try
begin catch
rollback tran
set transaction isolation level READ COMMITTED
end catch
set transaction isolation level READ COMMITTED
END
The table "test" has many values, so "select * from teste" takes several seconds. I run the sp_LockReader at same time in two diferent query windows and the second one starts showing test table contents without the first one terminates.
Shouldn't serializeble level forces the second query to wait?
How do i get the described behaviour?
Thanks
SERIALIZABLE at the most basic means "hold locks for longer". When you SELECT, the held lock is a shared lock which allows other readers.
If you want to block readers, use WITH (TABLOCKX) hint to take an exclusive lock where you don't need SERIALIZABLE. Or XLOCK with SERIALIZABLE
In other words:
SERIALIZABLE = Isolation Level = lock duration, concurrency
XLOCK = mode= sharing/exclusivity
TABLOCK = Granularity = what is locked
TABLOCKX = combined
See this question/answer for more info
A serializable transaction whose output is not affected by other concurrent transactions. In your case, you are SELECTing twice from the table; neither of those transactions changes the result set of the other, so they may both run simultaneously.
Even if one transaction did update the table, this would not necessarily prevent the other from executing, as the database may work from snapshots.
Have a look here for a better explanation than I can provide... http://en.wikipedia.org/wiki/Isolation_%28database_systems%29
Another note here. If you're using XLOCK under a SERIALIZABLE isolation, other transactions with READ COMMITTED isolation will still be able to read XLOCK'ed rows.
To prevent that, use PAGLOCK along with XLOCK.
See here for details
http://support.microsoft.com/kb/324417