当多个用户可以编辑相同数据时,首选数据库/ webapp并发设计

时间:2021-10-16 12:47:52

I have a ASP.NET C# business webapp that is used internally. One issue we are running into as we've grown is that the original design did not account for concurrency checking - so now multiple users are accessing the same data and overwriting other users changes. So my question is - for webapps do people usually use a pessimistic or optimistic concurrency system? What drives the preference to use one over another and what are some of the design considerations to take into account?

我有一个内部使用的ASP.NET C#业务webapp。我们遇到的一个问题是原始设计没有考虑并发检查 - 所以现在多个用户访问相同的数据并覆盖其他用户的更改。所以我的问题是 - 对于webapps,人们通常会使用悲观或乐观的并发系统吗?是什么驱使偏好使用一个而不是另一个以及需要考虑哪些设计考虑因素?

I'm currently leaning towards an optimistic concurrency check since it seems more forgiving, but I'm concerned about the potential for multiple changes being made that would be in contradiction to each other.

我目前倾向于乐观的并发检查,因为它似乎更宽容,但我担心可能会发生多次变化的可能性相互矛盾。

Thanks!

4 个解决方案

#1


3  

Optimistic locking.
Pessimistic is harder to implement and will give problems in a web environment. What action will release the lock, closing the browser? Leaving the session to time out? What about if they then do save their changes?

乐观锁定。悲观更难以实现,并会在Web环境中产生问题。什么动作会释放锁定,关闭浏览器?离开会议超时?如果他们然后保存他们的更改呢?

You don't specify which database you are using. MS SQL server has a timestamp datatype. It has nothing to do with time though. It is mearly a number that will get changed each time the row gets updated. You don't have to do anything to make sure it gets changed, you just need to check it. You can achive similar by using a date/time last modified as @KM suggests. But this means you have to remember to change it each time you update the row. If you use datetime you need to use a data type with sufficient precision to ensure that you can't end up with the value not changing when it should. For example, some one saves a row, then someone reads it, then another save happens but leaves the modified date/time unchanged. I would use timestamp unless there was a requirement to track last modified date on records.

您没有指定要使用的数据库。 MS SQL服务器具有时间戳数据类型。它与时间无关。它通常是每次更新行时都会更改的数字。你不需要做任何事情来确保它被改变,你只需要检查它。您可以使用@KM建议的最后修改日期/时间来实现类似。但这意味着每次更新行时都必须记住更改它。如果使用日期时间,则需要使用具有足够精度的数据类型,以确保不会最终得到不应更改的值。例如,有人保存一行,然后有人读取它,然后发生另一次保存,但保留修改的日期/时间。我会使用时间戳,除非有必要跟踪记录上的最后修改日期。

To check it you can do as @KM suggests and include it in the update statement where clause. Or you can begin a transaction, check the timestamp, if all is well do the update, then commit the transaction, if not then return a failure code or error.

要检查它,您可以像@KM建议的那样进行检查,并将其包含在update语句where子句中。或者你可以开始一个事务,检查时间戳,如果一切正常,那么提交事务,如果没有,则返回失败代码或错误。

Holding transactions open (as suggested by @le dorfier) is similar to pessimistic locking, but the amount of data locked may be more than a row. Most RDBM's lock at the page level by default. You will also run into the same issues as with pessimistic locking.

保持交易开放(如@le dorfier所建议)类似于悲观锁定,但锁定的数据量可能超过一行。大多数RDBM默认锁定在页面级别。您还将遇到与悲观锁定相同的问题。

You mention in your question that you are worried about conflicting updates. That is what the locking will prevent surely. Both optimistic or pessimistic will, when properly implemented prevent exactly that.

您在问题中提到您担心更新冲突。这就是锁定肯定会阻止的。乐观或悲观的意志,如果得到适当的实施,就会完全避免这种情况。

#2


3  

I agree with the first answer above, we try to use optimistic locking when the chance of collisions is fairly low. This can be easily implemented with a LastModifiedDate column or incrementing a Version column. If you are unsure about frequency of collisions, log occurrences somewhere so you can keep an eye on them. If your records are always in "edit" mode, having separate "view" and "edit" modes could help reduce collisions (assuming you reload data when entering edit mode).

我同意上面的第一个答案,当碰撞的可能性相当低时,我们尝试使用乐观锁定。这可以使用LastModifiedDate列或递增Version列轻松实现。如果您不确定碰撞的频率,请在某处记录事件,以便您可以密切关注它们。如果您的记录始终处于“编辑”模式,则具有单独的“查看”和“编辑”模式可以帮助减少冲突(假设您在进入编辑模式时重新加载数据)。

If collisions are still high, pessimistic locking is more difficult to implement in web apps, but definitely possible. We have had good success with "leasing" records (locking with a timeout)... similar to that 2 minute warning you get when you buy tickets on TicketMaster. When a user goes into edit mode, we put a record into the "lock" table with a timeout of N minutes. Other users will see a message if they try to edit a record with an active lock. You could also implement a keep-alive for long forms by renewing the lease on any postback of the page, or even with an ajax timer. There is also no reason why you couldn't back this up with a standard optimistic lock mentioned above.

如果冲突仍然很高,那么悲观锁定在Web应用程序中更难实现,但绝对可能。我们在“租赁”记录方面取得了很大成功(锁定超时)......类似于在TicketMaster上购买门票时得到的2分钟警告。当用户进入编辑模式时,我们将记录放入“锁定”表中,超时为N分钟。如果其他用户尝试使用活动锁编辑记录,则会看到一条消息。您还可以通过在页面的任何回发上更新租约,甚至使用ajax计时器来实现长表单的保持活动。也没有理由不能通过上面提到的标准乐观锁来支持这一点。

Many apps will need a combination of both approaches.

许多应用程序需要两种方法的组合。

#3


1  

here's a simple solution to many people working on the same records.

对于处理相同记录的许多人来说,这是一个简单的解决方案。

when you load the data, get the last changed date, we use LastChgDate on our tables

当您加载数据,获取最后更改的日期时,我们在表上使用LastChgDate

when you save (update) the data add "AND LastChgDate=previouslyLoadedLastChgDate" to the where clause. If the row count=0 on the update, issue error where "someone else has already saved this data" and rollback everything, otherwise the data is saved.

当您保存(更新)数据时,将“AND LastChgDate = previousLoadedLastChgDate”添加到where子句中。如果更新时行计数= 0,则发出错误,其中“其他人已保存此数据”并回滚所有内容,否则将保存数据。

I generally do the above logic on header tables only and not on the details tables, since they are all in one transaction.

我通常只在头表上执行上述逻辑,而不是在详细信息表上,因为它们都在一个事务中。

#4


0  

I assume you're experiencing the 'lost update' problem.

我假设您遇到了“丢失更新”问题。

To counter this as a rule of thumb I use pessimistic locking when the chances of a collision are high (or transactions are short lived) and optimistic locking when the chances of a collision are low (or transactions are long lived, or your business rules encompass multiple transactions).

为了对付这一点作为经验法则,当碰撞的可能性很高(或交易是短暂的)时,我会使用悲观锁定;当碰撞的可能性很低时(或者交易很长时间,或者您的业务规则包含在内),我会使用乐观锁定多个交易)。

You really need to see what applies to your situation and make a judgment call.

你真的需要看看什么适用于你的情况并做出判断。

#1


3  

Optimistic locking.
Pessimistic is harder to implement and will give problems in a web environment. What action will release the lock, closing the browser? Leaving the session to time out? What about if they then do save their changes?

乐观锁定。悲观更难以实现,并会在Web环境中产生问题。什么动作会释放锁定,关闭浏览器?离开会议超时?如果他们然后保存他们的更改呢?

You don't specify which database you are using. MS SQL server has a timestamp datatype. It has nothing to do with time though. It is mearly a number that will get changed each time the row gets updated. You don't have to do anything to make sure it gets changed, you just need to check it. You can achive similar by using a date/time last modified as @KM suggests. But this means you have to remember to change it each time you update the row. If you use datetime you need to use a data type with sufficient precision to ensure that you can't end up with the value not changing when it should. For example, some one saves a row, then someone reads it, then another save happens but leaves the modified date/time unchanged. I would use timestamp unless there was a requirement to track last modified date on records.

您没有指定要使用的数据库。 MS SQL服务器具有时间戳数据类型。它与时间无关。它通常是每次更新行时都会更改的数字。你不需要做任何事情来确保它被改变,你只需要检查它。您可以使用@KM建议的最后修改日期/时间来实现类似。但这意味着每次更新行时都必须记住更改它。如果使用日期时间,则需要使用具有足够精度的数据类型,以确保不会最终得到不应更改的值。例如,有人保存一行,然后有人读取它,然后发生另一次保存,但保留修改的日期/时间。我会使用时间戳,除非有必要跟踪记录上的最后修改日期。

To check it you can do as @KM suggests and include it in the update statement where clause. Or you can begin a transaction, check the timestamp, if all is well do the update, then commit the transaction, if not then return a failure code or error.

要检查它,您可以像@KM建议的那样进行检查,并将其包含在update语句where子句中。或者你可以开始一个事务,检查时间戳,如果一切正常,那么提交事务,如果没有,则返回失败代码或错误。

Holding transactions open (as suggested by @le dorfier) is similar to pessimistic locking, but the amount of data locked may be more than a row. Most RDBM's lock at the page level by default. You will also run into the same issues as with pessimistic locking.

保持交易开放(如@le dorfier所建议)类似于悲观锁定,但锁定的数据量可能超过一行。大多数RDBM默认锁定在页面级别。您还将遇到与悲观锁定相同的问题。

You mention in your question that you are worried about conflicting updates. That is what the locking will prevent surely. Both optimistic or pessimistic will, when properly implemented prevent exactly that.

您在问题中提到您担心更新冲突。这就是锁定肯定会阻止的。乐观或悲观的意志,如果得到适当的实施,就会完全避免这种情况。

#2


3  

I agree with the first answer above, we try to use optimistic locking when the chance of collisions is fairly low. This can be easily implemented with a LastModifiedDate column or incrementing a Version column. If you are unsure about frequency of collisions, log occurrences somewhere so you can keep an eye on them. If your records are always in "edit" mode, having separate "view" and "edit" modes could help reduce collisions (assuming you reload data when entering edit mode).

我同意上面的第一个答案,当碰撞的可能性相当低时,我们尝试使用乐观锁定。这可以使用LastModifiedDate列或递增Version列轻松实现。如果您不确定碰撞的频率,请在某处记录事件,以便您可以密切关注它们。如果您的记录始终处于“编辑”模式,则具有单独的“查看”和“编辑”模式可以帮助减少冲突(假设您在进入编辑模式时重新加载数据)。

If collisions are still high, pessimistic locking is more difficult to implement in web apps, but definitely possible. We have had good success with "leasing" records (locking with a timeout)... similar to that 2 minute warning you get when you buy tickets on TicketMaster. When a user goes into edit mode, we put a record into the "lock" table with a timeout of N minutes. Other users will see a message if they try to edit a record with an active lock. You could also implement a keep-alive for long forms by renewing the lease on any postback of the page, or even with an ajax timer. There is also no reason why you couldn't back this up with a standard optimistic lock mentioned above.

如果冲突仍然很高,那么悲观锁定在Web应用程序中更难实现,但绝对可能。我们在“租赁”记录方面取得了很大成功(锁定超时)......类似于在TicketMaster上购买门票时得到的2分钟警告。当用户进入编辑模式时,我们将记录放入“锁定”表中,超时为N分钟。如果其他用户尝试使用活动锁编辑记录,则会看到一条消息。您还可以通过在页面的任何回发上更新租约,甚至使用ajax计时器来实现长表单的保持活动。也没有理由不能通过上面提到的标准乐观锁来支持这一点。

Many apps will need a combination of both approaches.

许多应用程序需要两种方法的组合。

#3


1  

here's a simple solution to many people working on the same records.

对于处理相同记录的许多人来说,这是一个简单的解决方案。

when you load the data, get the last changed date, we use LastChgDate on our tables

当您加载数据,获取最后更改的日期时,我们在表上使用LastChgDate

when you save (update) the data add "AND LastChgDate=previouslyLoadedLastChgDate" to the where clause. If the row count=0 on the update, issue error where "someone else has already saved this data" and rollback everything, otherwise the data is saved.

当您保存(更新)数据时,将“AND LastChgDate = previousLoadedLastChgDate”添加到where子句中。如果更新时行计数= 0,则发出错误,其中“其他人已保存此数据”并回滚所有内容,否则将保存数据。

I generally do the above logic on header tables only and not on the details tables, since they are all in one transaction.

我通常只在头表上执行上述逻辑,而不是在详细信息表上,因为它们都在一个事务中。

#4


0  

I assume you're experiencing the 'lost update' problem.

我假设您遇到了“丢失更新”问题。

To counter this as a rule of thumb I use pessimistic locking when the chances of a collision are high (or transactions are short lived) and optimistic locking when the chances of a collision are low (or transactions are long lived, or your business rules encompass multiple transactions).

为了对付这一点作为经验法则,当碰撞的可能性很高(或交易是短暂的)时,我会使用悲观锁定;当碰撞的可能性很低时(或者交易很长时间,或者您的业务规则包含在内),我会使用乐观锁定多个交易)。

You really need to see what applies to your situation and make a judgment call.

你真的需要看看什么适用于你的情况并做出判断。