This is more of a knowledge sharing post.
Recently in one of my projects, I came across a issue which is pretty common, but never really gave it a thought till I faced it. There are number of solutions available, but somehow I did not find THE ONE I was looking for, which I am going to share in this post. I am sure many of you already know about the below solution, but for those who don't this can definitely be a life saver. :-)
Recently, I was working on a windows service. This service was supposed to insert some records into a table that long existed and being used by several other old services. There is a column (say “ID”) which holds an integer value. The logic written (probably years ago) to get the Integer to insert into this table is stated below:
The logic:
Code
SELECT @value = [Value] from [dbo].[Table1] WHERE [Name] = @Name;
UPDATE [dbo].[ Table1] SET [Value] = @value +1 WHERE [Name] = @Name;
SELECT @value = @value+1;
The technology used has Major Concurrency issues.
What is the best way to address such an issue - Considering this is referred to in many different applications/services?
Although it may seem like two users are updating the same row of data at the same time, the MySQL DBMS would prevent this from happening; instead one user's update would go first and one would go second. The result would be that both updates would go through (just not at the same time).
Concurrency occurs when two transactions operate currently on the same set of data. Concurrency can then lead to data inconsistency and abnormal behaviour for a transaction. RDBMS transactions have four properties, which are known as ACID, that ensure consistency of work.
What is Lost Update Concurrency Problem in SQL Server? The Lost Update Concurrency Problem happens in SQL Server when two or more transactions are allowed to read and update the same data. Let’s understand the Lost Update Concurrency Problem in SQL Server with an example.
Concurrency Control in SQL Server 1 A “Transaction” in SQL Server. The standard definition of a transaction states that “every query that runs in a SQL Server is in a transaction,” that means any query you ... 2 Transaction Properties. ... 3 Concurrency in SQL Server. ... 4 Solve Concurrency Problems. ... 5 Conclusion. ...
So, allowing concurrent transactions is essential from the performance point of view but allowing concurrent transactions may also introduce some concurrency issues when two or more transactions are working with the same data at the same time. The common concurrency problems that we get in SQL Server are as follows
1 Catch DbUpdateConcurrencyException during SaveChanges. 2 Use DbUpdateConcurrencyException.Entries to prepare a new set of changes for the affected entities. 3 Refresh the original values of the concurrency token to reflect the current values in the database. 4 Retry the process until no conflicts occur.
The obvious thought would be get rid of this piece and rewrite this. But there are times, particularly when you work on areas like this where certain logic, tables, codes are already getting referenced by several other programs, it is not an easy call.
My goal was to attack the root of the problem and get rid of it. If I can do that there are supposed to be no real impacts. The output of the proc would be the same, so to the outside world nothing actually changed. :-)
So, I did some minor tweaks to the above statements to ensure that every thread updates the value and reads the updated value. No more conflicts, no more dirty reads.
Updated Code
DECLARE @table table(
Value int NOT NULL
);
-- Update the value and output the same into a local table variable
UPDATE [dbo].[Table1] SET [Value] = [Value] + 1 OUTPUT inserted.[Value] INTO @table
WHERE [Name] = @Name
-- Now read the value from the local table variable
SELECT Value FROM @table;
For more information on output clause check https://msdn.microsoft.com/en-us/library/ms177564(v=sql.90).aspx
I ran some tests with a parallel.foreach (20,000 times). My test table had two entries -
If you check the attachment, you will find out the difference in the numbers.
Deadlock issues are hard to reproduce, but the problem with multiple threads reading the same value in clearly evident from the test result.
Any thoughts on this is most welcome.
As I said earlier, many of you would already know this solution, but for those who don't this can definitely save some time. :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With