处理数据库中的AJAX并发问题

时间:2013-08-30 12:03:08

标签: ajax postgresql concurrency

我们正在构建一个ajax应用程序。我们希望几个用户可以同时访问该应用程序。因此,我有想法以某种方式运行每个更新查询,以便它们提供字段的先前值。关键是如果前一个值不是系统预期的值,那么PostgreSQL应该抛出一个错误(这意味着在我们的用户被提供值之后,其他人修改了它)。在一个事务和数据库级别处理这个是很好的,因为没有并发问题。这可能吗?

3 个答案:

答案 0 :(得分:2)

  

因此,我有想法以某种方式运行每个更新查询,以便它们提供字段的先前值

您正在描述一种称为“乐观并发控制”或“乐观锁定”的技巧。它已经成熟并得到证实。

请参阅:

尽管ODBC使用的原始方法有一些......问题,但即使是年复一年的ODBC也做到了这一点。

拥有一个专用的修订列通常会好得多,该列应该是一个随每次更新而递增的整数。不要使用时间戳。

您可以执行以下操作:

SELECT col1, version FROM sometable WHERE id = 42;

想象一下,你得到结果行('bob',7),然后运行:

UPDATE sometable SET col1 = 'fred' WHERE id = 42 AND version = 7;

并检查受影响的行数。如果它为零,则表示存在更新冲突。

如果您将乐观锁定和传统应用程序混合在同一个数据库中,则可以使用a trigger to make sure the optimistic locking column always gets incremented,以便您的传统应用和操作锁定应用可以很好地协同工作。

顺便说一句,这个策略在PostgreSQL中的触发器分区表上不起作用

答案 1 :(得分:1)

如果你想在数据库中这样做,我认为你将不得不在表上使用触发器。在触发器中,您可以检查“旧”(现在表中的内容)与“新”(您要为更新发送的内容)。我不认为你可以使用规则。您还可以使用表中的最后一个修改列,而不是传递和比较所有列。

CREATE TRIGGER check_update
  BEFORE UPDATE ON table
  FOR EACH ROW
  WHEN (OLD.timestamp IS DISTINCT FROM NEW.timestamp)
  EXECUTE PROCEDURE check_update();

如果您不想使用时间戳,则可以在WHEN子句中进行所有列检查。然后,您可以让check_update()过程执行某些操作,可能会引发异常或返回现在存在的数据。可能有更好的方法,但这应该有效。

答案 2 :(得分:0)

postgreSQL MVCC模型可以确保在您的用户事务读取和保存数据更改时,没有人在更改数据。使用serializable transaction level ... 特别强制执行此操作。

你真正的问题不在于保存阶段,它可以很容易地打开事务,读取数据,更改它并提交此事务;你的问题是网络的事情。 您无法打开事务,读取数据,通过Web应用程序将其推送给最终用户,然后等待几秒钟/分钟的时间来获取ajax请求,然后保存更改的数据并提交。交易不会在很长时间内保持开放,并在用户发布后恢复。

因此,在Web应用程序服务器端,您拥有的是表单帖子,并且您希望保存更改的数据。您特别希望检测在用户加载页面,去吃东西之间以及决定按下提交按钮之间会改变的数据。一种方法是在用户帖子中存储原始未更改数据的副本,并将此数据与当前存储数据进行比较。另一种方法是使用@Scott S的解决方案(最后修改时间戳)来标记数据库中的数据记录。并在每次修改后重新计算它(可能使用触发器)。然后,您将在用户表单上嵌入此(或论文)数据签名,并在打开保存事务后,您要做的第一件事就是比较md5sum并在数据似乎已被更改时回滚整个操作。 / p>

这不是数据库角色,它是应用程序逻辑,因为数据库只管理异步数据操作(事务隔离管理和锁定)而不管理长期用户共享数据策略。您的应用程序必须通过异步表单lobd和posts处理共享策略。例如,参见维基百科处理它的方式。如果从多个位置以编辑模式加载同一页面并尝试同时保存两者,则会检测到先前的修改并拒绝第二次保存。要成为绝大多数网络应用程序的最佳人选,这个问题和最后一次提交都会赢得。

<强>更新

为了进一步使用ajax同步修改管理,您可以构建一个非常复杂的系统,使用LISTENNOTIFY SQL关键字来检测修改,并在客户端推回这些内容。如果您的应用程序服务器是持久的(不像PHP或jsp),并且如果您使用comet或其他push technology等系统进行持久性ajax连接仿真,则可以在其他用户拥有时通过Web表单通知用户使一个事务提交改变了他的表格中显示的一些数据。这不会消除用户在非常接近的时间提交修改的问题(并行用户请求处理服务器端)。对于最后一种情况,您唯一的解决方案是使用一个不错的交易,可能是可序列化的杠杆,始终管理用户修改可能被拒绝的事实(这是交易的关键,总是管理事务可以由服务器回滚,即使你没有犯错,只是因为修改与并行提交的事务冲突了。)