C# 多线程linq2sql应用程序TransactionScope困难

C# 多线程linq2sql应用程序TransactionScope困难,c#,multithreading,linq-to-sql,transactionscope,C#,Multithreading,Linq To Sql,Transactionscope,我创建了一个文件处理服务,它从特定目录读取和导入xml文件 该服务启动多个worker,这些worker将轮询文件队列以查找新文件,并使用linq2sql进行数据访问。每个workerthread都有自己的datacontext 正在处理的文件包含多个订单,每个订单包含多个地址(客户/承包商/分包商) 我已经围绕每个文件的处理定义了transactionscope。通过这种方式,我希望确保正确处理整个文件,或者在发生异常时回滚整个文件: try {

我创建了一个文件处理服务,它从特定目录读取和导入xml文件

该服务启动多个worker,这些worker将轮询文件队列以查找新文件,并使用linq2sql进行数据访问。每个workerthread都有自己的datacontext

正在处理的文件包含多个订单,每个订单包含多个地址(客户/承包商/分包商)

我已经围绕每个文件的处理定义了transactionscope。通过这种方式,我希望确保正确处理整个文件,或者在发生异常时回滚整个文件:

        try
        {
            using (var tx = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                foreach (var order in orders)
                {
                    HandleType1Order(order);
                }
                tx.Complete();
            }
        }
        catch (SqlException ex)
        {
            if (ex.Number == SqlErrorNumbers.Deadlock)
            {
                throw new FileHandlerException("File Caused a Deadlock, retrying later", ex, true);
            }
            else
                throw;
        }
该服务的一个要求是创建或更新xml文件中找到的地址。因此,我创建了一个地址服务,负责地址管理。对于xml导入文件()中的每个订单(在方法
HandleType1Order()
中)执行以下代码段,因此是整个文件的TransactionScope的一部分

我在这里要做的是创建或更新一个地址,并且号码是唯一的

方法
GetAddressByReference(字符串编号)
返回已知地址,如果找不到地址,则返回null

 public virtual Address GetAddressByReference(string reference)
 {
     return _addressRepository.GetAll().SingleOrDefault(a=>a.Code==reference);
 }
但是,当我运行该服务时,它会创建具有相同编号的多个地址。方法
GetAddressByReference()
get被并发调用,当第二个线程使用相同的addressnumber执行该方法时,该方法应返回一个已知地址,但返回null。我的事务边界或isolationlevel可能有问题,但我似乎无法让它正常工作

有人能给我指出正确的方向吗?非常感谢您的帮助

p、 我对事务被死锁并导致回滚没有问题,当死锁发生时,文件将被重试


编辑1线程代码:

        public void Work()
    {
        _isRunning = true;
        while (true)
        {
            ImportFileTask task = _queue.Dequeue(); //dequeue blocks on empty queue               
            if (task == null)
                break; //Shutdown worker when a null task is read from the queue

            IFileImporter importer = null;
            try
            {
                using (new LockFile(task.FilePath).Acquire()) //create a filelock to sync access accross all processes to the file
                {
                    importer = _kernel.Resolve<IFileImporter>();
                    Log.DebugFormat("Processing file {0}", task.FilePath);
                    importer.Import(task.FilePath);
                    Log.DebugFormat("Done Processing file {0}", task.FilePath);
                }
            }
            catch(Exception ex)
            {
                Log.Fatal(
                    "A Fatal exception occured while handling {0} --> {1}".FormatWith(task.FilePath, ex.Message), ex);
            }
            finally
            {
                if (importer != null)
                    _kernel.ReleaseComponent(importer);
            }

        }

        _isRunning = false;
    }
公共作废工作()
{
_isRunning=true;
while(true)
{
ImportFileTask task=\u queue.Dequeue();//清空队列上的队列块
如果(任务==null)
break;//从队列中读取空任务时关闭工作进程
IFileImporter importer=null;
尝试
{
使用(new LockFile(task.FilePath).Acquire())//创建一个文件锁,以同步所有进程对该文件的访问权限
{
导入器=_kernel.Resolve();
DebugFormat(“处理文件{0}”,task.FilePath);
importer.Import(task.FilePath);
DebugFormat(“已完成处理文件{0}”,task.FilePath);
}
}
捕获(例外情况除外)
{
日志。致命的(
“处理{0}-->{1}时发生致命异常”。FormatWith(task.FilePath,ex.Message),ex);
}
最后
{
如果(导入器!=null)
_内核发布组件(导入器);
}
}
_isRunning=false;
}

上述方法在所有工作线程中运行。它使用Castle Windsor解决FileImporter问题,FileImporter的生活方式是暂时的(因此没有共享线程)。

您没有发布线程代码,因此很难说问题出在哪里。我假设您已经启动了DTC(分布式事务协调器)

您正在使用线程池吗?你在使用“锁定”关键字吗


由于每个事务只使用一个SQLConnection,因此该事务不会升级为分布式事务。关于lock关键字,是的,我们使用同步,但我们正在尝试使用事务实现数据库访问同步(这是正确的方法,imho)
        public void Work()
    {
        _isRunning = true;
        while (true)
        {
            ImportFileTask task = _queue.Dequeue(); //dequeue blocks on empty queue               
            if (task == null)
                break; //Shutdown worker when a null task is read from the queue

            IFileImporter importer = null;
            try
            {
                using (new LockFile(task.FilePath).Acquire()) //create a filelock to sync access accross all processes to the file
                {
                    importer = _kernel.Resolve<IFileImporter>();
                    Log.DebugFormat("Processing file {0}", task.FilePath);
                    importer.Import(task.FilePath);
                    Log.DebugFormat("Done Processing file {0}", task.FilePath);
                }
            }
            catch(Exception ex)
            {
                Log.Fatal(
                    "A Fatal exception occured while handling {0} --> {1}".FormatWith(task.FilePath, ex.Message), ex);
            }
            finally
            {
                if (importer != null)
                    _kernel.ReleaseComponent(importer);
            }

        }

        _isRunning = false;
    }