Rows lock - manually using(different transactions) - sql-server

I want to make a lock mechanism like that, but I'm not sure it possible or not.
First, Lock a row in temporary table(with select statement and output data to application)
Next, I make some other transactions(Insert, Update to another table)
And then release the locked row.
In that time, Any select statement that want to get data from locked row should wait

All you need is the strictest transaction isolation level, it will prevent other users to access the rows even when you are only reading the row.
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
SELECT * FROM TableName WHERE <some row>
UPDATE <Statement>
COMMIT TRANSACTION;

See this article KB324417 and try this:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
SELECT * FROM TableName (XLOCK, PAGLOCK) WHERE <some row>
UPDATE <Statement>
COMMIT TRANSACTION;

Related

Pattern for simple table lock in SQL Server

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?

tSQL 2012 - table locking within TRANSACTION

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

T-SQL lock resouce in an event of concurrent access

I want to lock a certain table in the event of concurrent access.
Inside a stored procedure:
I truncate a table
Do calculations and populate the above table
After returning from PROCEDURE, do a select from the table
To avoid issues in event of concurrent access, I am planning to add a 'BEGIN TRANSACTION' followed by 'BEGIN TRY -END TRY' and 'BEGIN CATCH - END CATCH'. I 'COMMIT' just before 'END-TRY' and 'ROLLBACK' inside the 'CATCH'.
Will this alone resolve all concurrency issues or I need to do something more.
Many thanks,
Sujit
You could lock entire table during a transaction using TABLOCK or TABLOCKX (references):
BEGIN TRANSACTION;
-- For shared locking:
-- This will take a S(shared) lock at table level for duration of transaction
-- SELECT TOP(0) * FROM dbo.MyTable WITH(TABLOCK,HOLDLOCK)
-- HOLDLOCK hint is needed in this case because
-- default behavior at default transaction isolation level (READ COMMITTED)
-- is to maintain a S lock only during record reading.
-- For exclusive locking:
-- This will take a (x)X(clusive) lock at table level for duration of transaction
SELECT TOP(0) * FROM dbo.MyTable WITH(TABLOCKX)
ROLLBACK;
Example (SQL Profiler output):
Note: SELECT OBJECT_ID(N'dbo.MyTable') = 1316199739

Lock a row in a table SQL Server

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

Fixing upsert issue with 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.

Resources