首页 > 解决方案 > 解决数据库竞争条件的最佳方法

问题描述

我有一个保存电影字幕的应用程序。我需要防止出现 2 个字幕重叠的情况。首先,我将定义什么是重叠字幕。假设字幕类有 MovieId、EntryTime、ExistTime 和 Text。EntryTime 是一个数字,表示在电影中显示字幕的时间(以毫秒为单位),而 ExistTime 是在电影中消失的时间。如果我们有 2 个标题如下

var caption1 = new Caption(){MovieId = 1, EntryTime = 100, ExistTime =200}
var caption2 = new Caption(){MovieId = 1, EntryTime = 120, ExistTime =220}

它们是重叠的,但以下标题不是

var caption3 = new Caption(){MovieId = 1, EntryTime = 400, ExistTime =450}
var caption4 = new Caption(){MovieId = 2, EntryTime = 425, ExistTime =470}

所有电影的所有字幕都保存在同一个数据库中,数据库中有同一个表。

为了避免插入重叠的标题,我首先尝试在我的服务器代码中加锁。此代码专门检查标题的 EntryTime 和 EndTime 并且不检查重叠场景,但此检查应支持重叠情况

  lock (insertCaptionLocker)
                    {
                        var captionExists = dbCaptions.Captions.Any(x =>
                                x.MovieId == caption.MovieId && x.EntryTime == caption.EntryTime &&
                                x.ExitTime == caption.ExitTime);

                        if (!captionExists)
                        {

                            dbCaptions.Captions.InsertOnSubmit(caption);
                        }

                        dbCaptions.SubmitChanges();
                    }

我对这段代码有一些问题:

  1. 它并不总是一个关键部分 - 大多数时候允许超过 1 个线程进入此代码应该是可以的。仅当我们有 2 个线程(或更多)尝试更新具有重叠时间的相同 MovieId 时,我们才会遇到问题。
  2. 如果我们有超过 1 个服务器与负载平衡器连接,它将无法工作。

我认为解决方案应该以某种方式来自数据库,但我不知道该使用什么。任何帮助将不胜感激。

标签: c#sql-servermultithreadingrace-condition

解决方案


一个观察:

您的条件仅检查给定 MovieId 是否已经存在具有相同 EntryTime 和 ExistTime 的字幕,它不会检查它们是否重叠。

对于非重叠,您应该检查类似这样的内容,检查每对的开始和结束时间:

var non_overlapping = dbCaptions.Captions.Any(x =>
x.MovieId == caption.MovieId &&( x.EntryTime < caption.EntryTime && x.ExitTime < caption.EntryTime || x.EntryTime > caption.EntryTime && caption.ExitTime < x.EntryTime )

这对将不重叠,因此您可以插入它们。使用您的方法,您将获得完全相同的标题,但不是所有重叠的标题,ypu 还可以定义一个范围并检查您的元组(x.EntryTime ,x.ExitTime)是否在range(caption.EntryTime ,caption.ExitTime).


推荐阅读