I've been reading the MSDN about transaction isolation levels and table hints in an effort to find out what I need to do to exclusively lock a table while I perform a 2 step insert in SQL Server. I've come up with 2 ways to do it and would like to know what the difference is between the approaches.
This answer shows how to do it with hints (https://stackoverflow.com/a/23759307/545430):
--Enclose steps in transaction to define an atomic operation
BEGIN TRAN
-- Perform an insert that locks tblMoo
INSERT INTO tblMoo SET fldCow='valPie' WITH (TABLOCKX, SERIALIZABLE)
UPDATE tblMoo SET fldCowIndex=(SELECT MAX(fldCowIndex) + 1)
COMMIT TRAN
I think I could also achieve my objective by setting the isolation level:
BEGIN TRAN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
INSERT blah blah blah
UPDATE hoo dee dah
COMMIT TRAN
It is important that I lock the entire table from any updates while my transaction is inserting this new row. Would both approaches yield the same result: the table being locked for both the INSERT and UPDATE commands?
Related
I need to answer two questions. Here's an overview:
I have 3 tables:
CREATE TABLE A(x INT)
CREATE TABLE B(x INT)
CREATE TABLE C(x INT)
and 2 triggers:
ALTER TRIGGER ATr ON A
FOR INSERT AS
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
INSERT INTO B
SELECT *
FROM inserted;
COMMIT
END
ALTER TRIGGER BTr ON B
FOR INSERT AS
BEGIN
INSERT INTO C
SELECT * FROM inserted;
END
and the INSERT triggering the ATr trigger INSERT INTO A VALUES(3) is done on REPEATABLE READ isolation level, and the default isolation level for this database is READ COMMITTED.
And I need to answer two questions:
On which isolation level will the ATr trigger execute?
On which isolation level will the BTr trigger execute (if at all)?
I have problem understanding how these nested transactions are going to work. Will any transaction inside a LEVEL SERIALIZABLE transaction ever execute? Are they even nested in this case? What happens if a lower isolation level is inside a higher isolation level or the other way around?
The behavior is documented here SET TRANSACTION ISOLATION LEVEL
And you can examine this behavior by running
select CASE transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'ReadUncomitted'
WHEN 2 THEN 'ReadCommitted'
WHEN 3 THEN 'Repeatable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot' END AS transaction_isolation_level
from sys.dm_exec_requests
where session_id = ##spid
wherever you are curious about the currently-active isolation level.
Two SP's are getting executed one after another and the second one is getting blocked by first one. They both are trying to update same table. Two SP's are as following
CREATE PROCEDURE [dbo].[SP1]
Begin
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRANSACTION ImpSchd
update Table t1 .......... ................................//updating
a set of [n1,n2....n100] records
COMMIT TRANSACTION ImpSchd
SET TRANSACTION ISOLATION LEVEL
READ COMMITTED;
END
2.
CREATE PROCEDURE [dbo].[SP2]
Begin
update Table t1 .......... ................................//updating
a set of [n101,n102.....n200] records
END
My question is when sp1 is running is snapshot level isolation why is it blocking sp2 (n both are updating different set of records)?
If i run first sp for two different set of records simultaneously it
works perfectly.
How can I overcome this situation ?
If using the snapshot level isolation is to be set for each sp updating the same table then it would be a larger change.
if two sp has to update same records in a table, how should i handle that(both sp will update different columns)?
Isolation levels only are for not blocking selects,so any DML wont be affected by Isolation levels.In this case update takes IX lock on table,page followed by taking xlock on row to update.Since you are updating in bulk ,table itself might have been locked due to lock escalation.Hope this helps
I have the following TRANSACTION structure:
BEGIN TRY
BEGIN tran sometransaction
INSERT INTO local_table_1 (columns...)
SELECT (columns...)
FROM remote_table
WHERE (conditions, predicates)
UPDATE local_table_1
SET column_A = value
WHERE....
UPDATE local_table_1
SET column_B = value
WHERE....
UPDATE local_table_1
SET column_C = value
WHERE....
COMMIT tran sometransaction
END TRY
BEGIN catch
ROLLBACK tran sometransaction
END catch
I want to make sure that no one is allowed to read contents of local_table_1 unless all statements within this transaction are over and have been committed.
Is there a way to set WITH (TABLOCKX, HOLDLOCK) on the whole transaction? I understand that tables lock automatically during the transaction execution however I could not find any explanation if that extends on external concurrent read processes.
Thank you.
An external process will not read uncommitted transactions unless your external process is using a NOLOCK hint or READ UNCOMMITTED isolation. This is all related to Isolation in reference to the ACID properties of sql. http://en.wikipedia.org/wiki/ACID
Set the transaction isolation level to READ COMMITTED or REPEATABLE READ before you begin your transaction. The following link has a description and example:
http://msdn.microsoft.com/en-us/library/ms173763.aspx
I need to lock a row in a table so no one can read this line while I'm running a procedure. I am using BEGIN TRAN in this procedure. So, this record I'm trying to block is uncommitted during the process.
Is it possible?
Depending on what is the purpose of your stored procedure:
- In case it modifies the mentioned row, you can base on transaction levels
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
--UPDATE/INSERT/DELETE your row here
...
COMMIT TRANSACTION
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
- Use lock hints
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT column1, column2
FROM yourTable WITH (ROWLOCK)
WHERE ID = YourRecordId
...
COMMIT TRANSACTION
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
I have a SQL statement that does an update, and then if the ##ROWCOUNT is 0, it will insert. this is basically a MERGE in SQL 2008. We are running into situations where two threads are failing on the update simultaneously. It will attempt to insert the same key twice in a table. We are using the Default Transaction isolation level, Read Committed. Will changing the level to repeatable reads fix this or do I have to go all the way to Serializable to make this work? Here is some code:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRAN;
UPDATE TableA
SET Duration = #duration
WHERE keyA = #ID
AND keyB = #IDB;
IF ##rowcount = 0
BEGIN
INSERT INTO TableA (keyA,keyB,Duration)
VALUES (#ID,#IDB,#duration);
END
COMMIT TRAN;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;";
You would need to go all the way up to SERIALIZABLE.
Under REPEATABLE READ if the row does not exist then both UPDATE statements can run concurrently without blocking each other and proceed to do the insert. Under SERIALIZABLE the range where the row would have been is blocked.
But you should also consider leaving the isolation level at default read committed and putting a unique constraint on keyA,keyB so any attempts to insert a dupe fail with an error.