Using SQL dB column as a lock for concurrent operations in Entity Framework

跟風遠走 提交于 2019-12-13 02:57:44

问题


We have a long running user operation that is handled by a pool of worker processes. Data input and output is from Azure SQL.

The master Azure SQL table structure columns are approximated to

[UserId, col1, col2, ... , col N, beingProcessed, lastTimeProcessed ] 

beingProcessed is boolean and lastTimeProcessed is DateTime. The logic in every worker role is as shown below and with multiple workers processing (each with their own Entity Framework layer), in essence beingProcessed is being used a lock for MutEx purposes

Question: How can I deal with concurrency issues on the beingProcessed "lock" itself based on the above load? I think read-modify-write operation on the beingProcessed needs to be atomic but I'm open to other strategies. Open to other code refinements too.

[Update]: I wonder if TransactionScope is what's needed here ... http://msdn.microsoft.com/en-US/library/system.transactions.transactionscope(v=vs.110).aspx

Code:

public void WorkerRoleMain()
{
    while(true)
    {
        try
        {
            dbContext db = new dbContext();

            // Read
            foreach (UserProfile user in db.UserProfile
                    .Where(u => DateTime.UtcNow.Subtract(u.lastTimeProcessed) 
                            > TimeSpan.FromHours(24) & 
                            u.beingProcessed == false))
            {
                user.beingProcessed = true; // Modify
                db.SaveChanges();           // Write
                // Do some long drawn processing here
                ...
                ...
                ...
                user.lastTimeProcessed = DateTime.UtcNow;
                user.beingProcessed = false;
                db.SaveChanges();
            }
        }
        catch(Exception ex)
        {
            LogException(ex);
            Sleep(TimeSpan.FromMinutes(5));
        }
    } // while ()
}

回答1:


What we usually do is this:

At the beginning of a long operation we start a transaction:

BEGIN TRANSACTION

Then we select a row from the table we would like to update/delete using these hints:

SELECT * FROM Table WITH (ROWLOCK, NOWAIT) Where ID = 123;

Then we check that we have the row. If the row is locked by another process there will be an SQL Error. In this case we rollback the transaction and advise the user. If the record is locked we process the record, and do the required updates, using the same transaction object we used to lock the record:

UPDATE Table SET Col1='value' WHERE ID = 123;

Then we COMMIT the transaction.

COMMIT;

This is just the Pseudo-code of the process. You will have to implement it in your program.

One small note regarding the above process. When you lock the record in SQL Server (or Azure), use the primary key in your WHERE Clause, otherwise the SQL Server will decide to use a Page lock, or Table lock



来源:https://stackoverflow.com/questions/13850180/using-sql-db-column-as-a-lock-for-concurrent-operations-in-entity-framework

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!