SQL Server knowledge center

everything about SQL Server
See also: Other Geeks@INDC

Implement Concurrency-Safe Stored Procedure for Update and Delete

Implement Concurrency-Safe Stored Procedure for Update and Delete
In SQL Server 2005

By : Kasim Wirama, MCDBA

 

Concurrency happens when two or more users access and modifies same resource. In this article, I would share would how you should develop UD (Update, Delete) stored procedure that is aware to concurrency so that your users ensure that changes that they make will be consistent.

 

Create 2 tables, first invoice and then invoiceLineItem as script shown below :

 

CREATE TABLE dbo.Invoice

(

  InvoiceId int identity(1,1),

  InvoiceDate datetime,

  InvoiceNumber varchar(30) not null,

  Constraint pk_invoice primary key (InvoiceId),

  Constraint ak_invoice unique (InvoiceNumber)

);

GO

CREATE TABLE dbo.InvoiceLineItem

(

  InvoiceLineItemId int identity(1,1) not null,

  InvoiceId int not null,

  Cost numeric (10,2),

  Constraint pk_invoiceLineItem primary key (InvoiceLineItemId),

  Constraint fk_invoiceLineItem foreign key (InvoiceId)                                                             References dbo.Invoice(InvoiceId)

);

GO

 

Now let’s say you create a stored procedure to delete one of the invoiceLineItem as follows :

 

CREATE PROCEDURE dbo.InvoiceLineItem_del

(@InvoiceLineItemId int)

As

BEGIN

  DELETE FROM dbo.InvoiceLineItem

  WHERE InvoiceLineItemId = @InvoiceLineItemId

END;

GO

 

It’s simple but I can say it’s not safe against concurrency issue. Let’s say, user A change cost at a InvoiceLineItem. With almost the same time, user B call the stored procedure to delete the InvoiceLineItem. Boom! User B successfully delete the invoiceLineItem without knowing before hand that there was a change in InvoiceLineItem made by other user, i.e. UserA. That’s the concurrency issue.

 

So the stored procedure above is not capable to handle concurrency issue, and unfortunately I saw many projects get used to with this kind of CRUD style which is not concurrency safe.

How to make it concurrency safe? Here I will tell you a trick. The tirck is that I add rowversion at Invoice and implement high performance server side transaction scope that binds Invoice and InvoiceLineItem into one transaction. So I add new column at Invoice table as following script shown:

 

ALTER TABLE dbo.Invoice

            ADD ObjectVersion rowversion;

 

Now change the above stored procedure as follow :

 

ALTER PROCEDURE dbo.InvoiceLineItem_del

(

  @InvoiceLineItemId int ,

  @InvoiceId int ,

  @objectVersion rowversion

)

As

BEGIN

  BEGIN TRY

            BEGIN TRAN;

           

            UPDATE dbo.Invoice

            SET InvoiceNumber = InvoiceNumber

            WHERE InvoiceId = @InvoiceId

                        AND ObjectVersion = @objectVersion;

 

            IF @@ROWCOUNT = 0

                        RAISERROR (‘Changes has been happened prior deleting line item’, 16, 1)      ;

 

            DELETE dbo.InvoiceLineItem

            WHERE InvoiceLineItemId = @InvoiceLineItemId;

 

            COMMIT TRAN;

  END TRY

  BEGIN CATCH

            IF xact_state() <> 0

                        BEGIN

                                    ROLLBACK TRAN;

                        END

            DECLARE @errmsg VARCHAR(8000);

            SET @errmsg = ERROR_MESSAGE();

            RAISERROR ( @errmsg, 16, 1);

  END CATCH;

END;

GO

 

With the concurrency-safe stored procedure above, your users will be aware changes made from others before hand.

Share this post: | | | |

Comments

Irwansyah said:

Bukannya yg mau dicegah supaya user tidak delete invoice line item yg sudah diupdate?

"Let’s say, user A change cost at a InvoiceLineItem. With almost the same time, user B call the stored procedure to delete the InvoiceLineItem. Boom! User B successfully delete the invoiceLineItem without knowing before hand that there was a change in InvoiceLineItem made by other user, i.e. UserA. That’s the concurrency issue.

"

Kalau dengan sp diatas bukannya tetap bisa kedelete walaupun invoice line item sudah berubah? CMIIW

# March 16, 2008 12:53 AM

Kasim Wirama said:

perhatikan ada tambahan input parameter rowversion, skenario yg mungkin terjadi adalah userA dan userB sama-sama membaca dan kemudian sama-sama merubah, otomatis user yang paling akhir akan mendapatkan rowversion yang sudah berubah dibandingkan dengan rowversion pada saat pertama kali dibaca. Get the idea?

# March 17, 2008 11:18 AM

Kasim Wirama said:

"Bukannya yg mau dicegah supaya user tidak delete invoice line item yg sudah diupdate?"

Answer : SP itu memastikan hanya ada 1 user yg melakukan perubahan pada satu satuan waktu (one at a time), dan hasilnya konsisten bagi semua user.

# March 17, 2008 11:48 AM

Irwansyah said:

No, gw belom get the idea. SP di atas cuma memeriksa apakah dbo.Invoice sudah dirubah atau belum, tetapi tidak memeriksa apakah InvoiceLineItem sudah berubah atau belum sebelum dihapus.

# March 17, 2008 9:09 PM

Kasim Wirama said:

"SP di atas cuma memeriksa apakah dbo.Invoice sudah dirubah atau belum"

Not correct, justru memeriksa apakah ada perubahan antar InvoiceLineItem.

InvoiceLineItem tidak berdiri namun terkait dengan Invoice membentuk satu entity, sehingga concurrency terjadi pada 1 entity. Sebagai 1 entity, penambahan rowversion cukup pada Invoice. Database perlu aware concurrency diantara InvoiceLineItem, yang merubah komposisi dari entity Invoice.

Bisa dibayangkan kekacauan yang terjadi bila 2 atau lebih user secara bersamaan melakukan modifikasi pada entity yang sama.

Katakanlah jumlah InvoiceLineItem ada 4 untuk sebuah invoice. User A mengira dia hanya melakukan perubahan harga dan jumlah LineItem adalah 4, User B menghapus salah satu dari item sehingga jumlah item yang seharusnya menjadi 3, User C mengupdate harga menjadi 2 kali lipat untuk semua line item dan user C berpikir bahwa jumlah line item tetap 4. Bagaimana memaintain concurrency antar InvoiceLineItem dalam 1 invoice antara user A, user B, dan user C? Jawabannya kembali pada penjelasan pada paragraf pertama.

Concurrency merupakan hal yang kompleks, dan memang butuh kejelian untuk memilah mana yang berpotensi menimbulkan isu concurrency dengan review secara seksama terhadap skenario yang mungkin terjadi.

# March 18, 2008 5:23 AM

irwansyah said:

OK, I get the idea. Berarti yang kurang bukan di SP tetapi artikelnya tidak menyebutkan secara ekplisit skenario-skenario yang mungkin terjadi. :)

# March 20, 2008 10:51 AM

Kasim Wirama said:

Rasanya sudah saya sebutkan, berikut paragraf yang saya copy paste

"Let’s say, user A change cost at a InvoiceLineItem. With almost the same time, user B call the stored procedure to delete the InvoiceLineItem. Boom! User B successfully delete the invoiceLineItem without knowing before hand that there was a change in InvoiceLineItem made by other user, i.e. UserA. That’s the concurrency issue."

# March 20, 2008 4:06 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 
Are you human?:  


Enter the numbers above: