TransactionScope 的细微差别

发布于 2024-10-17 12:15:56 字数 1073 浏览 2 评论 0原文

假设我有两个线程,它们在特定于线程的 TransactionScope 中执行一些面向数据库的代码,并且具有 ReadCommissed 隔离级别。但是有一些表的数据应该共享(不应创建重复项)。

using (var transactionScope = new TransactionScope(IsolationLevel.ReadCommitted))
{
   ...//some code
   if (!_someRepository.IsValueExists(value))
      _someRepository.AddData(value);
   ...//some code
   transactionScope.Complete();
}

问题是两个线程可能几乎同时检查数据是否存在,如果不存在,则创建重复的数据(约束在这里无济于事:我必须防止异常情况发生)。我想这是一个微不足道的问题,但通常是如何解决的?

我看到以下示意性解决方案:

using (var transactionScope = new TransactionScope(IsolationLevel.ReadCommitted))
{
   ...//some code
   transactionScope.IsolationLevel = IsolationLevel.ReadUncommitted; //change Isolation Level
   lock (_sharedDataLockObject)
   {
      if (!_someRepository.IsValueExists(value))
         _someRepository.AddData(value);
   }
   transactionScope.IsolationLevel = IsolationLevel.ReadCommitted; //reset IsolationLevel
   ...//some code
   transactionScope.Complete();
}

该解决方案的第一个问题是 TransactionScope 不支持 IsolationLevel 修改。但假设我在这里使用 ADO.NET 事务。不过我不确定它是否有效。

Let's imagine I have two threads which execute some database-oriented code in thread-specific TransactionScopes with ReadCommitted isolation level. But there is some table which data should be shared (no duplicates should be created).

using (var transactionScope = new TransactionScope(IsolationLevel.ReadCommitted))
{
   ...//some code
   if (!_someRepository.IsValueExists(value))
      _someRepository.AddData(value);
   ...//some code
   transactionScope.Complete();
}

The problem is both threads may check whether data exists at just about same time and if not - create duplicated data (constrains won't help here: I have to prevent exceptional situation to happen). I guess it is a trivial problem but how is it usually solved?

I see the following schematical solution:

using (var transactionScope = new TransactionScope(IsolationLevel.ReadCommitted))
{
   ...//some code
   transactionScope.IsolationLevel = IsolationLevel.ReadUncommitted; //change Isolation Level
   lock (_sharedDataLockObject)
   {
      if (!_someRepository.IsValueExists(value))
         _someRepository.AddData(value);
   }
   transactionScope.IsolationLevel = IsolationLevel.ReadCommitted; //reset IsolationLevel
   ...//some code
   transactionScope.Complete();
}

The first problem with this solution is that TransactionScope doesn't support IsolationLevel modification. But let's imagine I use ADO.NET transaction here. Nevertheless I'm not sure whether it works.

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

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

发布评论

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

评论(2

总攻大人 2024-10-24 12:15:56

在这种情况下,我会进行双重检查。

首先检查它不存在,这里不需要交易。

然后启动可序列化事务。

检查是否仍然不存在,

如果不存在则添加

提交并关闭事务。

In this case I would do a double check.

First check that it does not exist, no need for a transaction here.

Then start a serializable transaction.

Check that it still does not exist

if not exists add

commit and close the transaction.

喜爱纠缠 2024-10-24 12:15:56

我通常使用数据库约束来解决完全相同的问题,并将整个事务包装在 try-catch 中,并在 catch 块中重试。当然,如果由于某种原因无法重新启动事务,这不是一个有效的解决方案(例如事务在您的控制之外启动 - 我不确定您的意思是“我必须防止异常情况发生” ”)。

根据事务通常花费的时间,您可能需要在重试之前稍等一下或重试几次,但只要并行事务已成功完成,您的重试就会成功。

棘手的部分通常是如何确定异常是由特定约束违规引起的。这通常需要一些经验测试来确定确切的异常类型以及异常消息的一些丑陋的字符串匹配。

I usually solve the exact same problem with a DB constraint and by wrapping the entire transaction in a try-catch with a retry in the catch block. Of course, if it is not possible to restart the transaction for some reason this is not a valid solution (e.g. the transaction is started outside of your control - I'm not sure what you mean by "I have to prevent exceptional situation to happen").

Depending on how long time the transactions usually take you may want to wait a little before the retry or make a couple of retries but as long as the parallel transaction has completed successfully your retry will succeed.

The tricky bit is often how to determine that the exception was caused by a particular constraint violation. This usually requires some empirical testing to determine the exact exception type and some ugly string matching of the exception message.

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