使用SQL dB列作为实体框架中并发操作的锁 [英] Using SQL dB column as a lock for concurrent operations in Entity Framework

查看:251
本文介绍了使用SQL dB列作为实体框架中并发操作的锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个长时间运行的用户操作,由一组工作进程处理。数据输入和输出来自Azure SQL。

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

主Azure SQL表结构列近似为

The master Azure SQL table structure columns are approximated to

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

beingProcessed 是布尔值,而 lastTimeProcessed 是DateTime。每个工作人员角色的逻辑如下所示,并且多个工作者处理(每个都有自己的实体框架层),实质上 beingProcessed 正在使用MutEx目的的锁

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

问题:如何处理 isProcessed 锁定本身的并发问题基于上述负载?我认为 isProcessed 中的 read-modify-write 操作需要是原子的,但我对其他策略开放。

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.

[更新]:我想知道 TransactionScope 是否需要在这里? http://msdn.microsoft。 com / en-US / library / system.transactions.transactionscope(v = vs.110).aspx

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

代码:

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 ()
}


推荐答案

我们通常做的是这样的:

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;

然后我们检查一下我们有这行。如果行被其他进程锁定,则会出现SQL错误。在这种情况下,我们回滚交易并建议用户。
如果记录被锁定,我们处理记录,并使用我们用于锁定记录的相同事务对象进行所需的更新:

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;

然后我们提交交易。

COMMIT;

这只是进程的伪代码。你将不得不在你的程序中实现它。

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

有关上述过程的一个小笔记。在SQL Server(或Azure)中锁定记录时,请使用WHERE子句中的主键,否则SQL Server将决定使用Page lock或Table lock

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

这篇关于使用SQL dB列作为实体框架中并发操作的锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆