对于下面的 insert-if-not-present 事务,我应该使用哪个隔离级别?

发布于 2024-09-02 11:42:36 字数 819 浏览 9 评论 0原文

我编写了一个 linq-to-sql 程序,该程序本质上执行 ETL 任务,并且我注意到并行化可以提高其性能的许多地方。但是,我担心当两个线程执行以下任务(伪代码)时防止唯一性约束违规。

Record CreateRecord(string recordText)
{
    using (MyDataContext database = GetDatabase())
    {
        Record existingRecord = database.MyTable.FirstOrDefault(record.KeyPredicate());
        if(existingRecord == null)
        {
            existingRecord = CreateRecord(recordText);
            database.MyTable.InsertOnSubmit(existingRecord);
        }

        database.SubmitChanges();
        return existingRecord;
    }
}

一般来说,此代码执行 SELECT 语句来测试记录是否存在,如果记录不存在,则执行 INSERT 语句。它由隐式事务封装。

当两个线程为 recordText 的同一个实例运行此代码时,我想防止它们同时确定该记录不存在,从而都尝试创建相同的记录。隔离级别和显式事务可以很好地工作,但我不确定应该使用哪种隔离级别 - Serialized 应该可以工作,但似乎太严格了。还有更好的选择吗?

I've written a linq-to-sql program that essentially performs an ETL task, and I've noticed many places where parallelization will improve its performance. However, I'm concerned about preventing uniquness constraint violations when two threads perform the following task (psuedo code).

Record CreateRecord(string recordText)
{
    using (MyDataContext database = GetDatabase())
    {
        Record existingRecord = database.MyTable.FirstOrDefault(record.KeyPredicate());
        if(existingRecord == null)
        {
            existingRecord = CreateRecord(recordText);
            database.MyTable.InsertOnSubmit(existingRecord);
        }

        database.SubmitChanges();
        return existingRecord;
    }
}

In general, this code executes a SELECT statement to test for record existance, followed by an INSERT statement if the record doesn't exist. It is encapsulated by an implicit transaction.

When two threads run this code for the same instance of recordText, I want to prevent them from simultaneously determining that the record doesn't exist, thereby both attempting to create the same record. An isolation level and explicit transaction will work well, except I'm not certain which isolation level I should use -- Serializable should work, but seems too strict. Is there a better choice?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

神仙妹妹 2024-09-09 11:42:36

我使用类似于下面所示的 SQL 来避免这种情况。 UPDLOCK 指定在事务完成之前获取并保留更新锁,并且 HOLDLOCK 相当于 SERIALIZABLESERIALIZABLE 通过持有共享锁直至事务完成来使共享锁更具限制性,而不是在不再需要所需的表或数据页时立即释放共享锁,无论事务是否已完成。扫描的执行语义与在SERIALIZABLE 隔离级别运行的事务相同。 HOLDLOCK 仅适用于为其指定的表或视图,并且仅适用于由使用它的语句定义的事务持续时间。HOLDLOCK 不能用于包含 FOR BROWSE 选项的 SELECT 语句。

declare @LocationID          int
declare @LocationName        nvarchar (50)

/* fill in LocationID and LocationName appropriately */

INSERT dbo.Location
(LocationID, LocationName)
SELECT @LocationID, @LocationName
WHERE NOT EXISTS (
   SELECT L.*
   FROM dbo.Location L WITH (UPDLOCK, HOLDLOCK)
   WHERE L.LocationID = @LocationID)

根据这个问题的答案,Serialized似乎是可行的方法。

I use SQL similar to what is shown below to avoid such situations. UPDLOCK specifies that update locks are to be taken and held until the transaction completes and HOLDLOCK is equivalent to SERIALIZABLE. SERIALIZABLE makes shared locks more restrictive by holding them until a transaction is completed, instead of releasing the shared lock as soon as the required table or data page is no longer needed, whether the transaction has been completed or not. The scan is performed with the same semantics as a transaction running at the SERIALIZABLE isolation level. HOLDLOCK applies only to the table or view for which it is specified and only for the duration of the transaction defined by the statement that it is used in. HOLDLOCK cannot be used in a SELECT statement that includes the FOR BROWSE option.

declare @LocationID          int
declare @LocationName        nvarchar (50)

/* fill in LocationID and LocationName appropriately */

INSERT dbo.Location
(LocationID, LocationName)
SELECT @LocationID, @LocationName
WHERE NOT EXISTS (
   SELECT L.*
   FROM dbo.Location L WITH (UPDLOCK, HOLDLOCK)
   WHERE L.LocationID = @LocationID)

According to the answer to this question, Serializable seems to be the way to go.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文