处理并发问题的最佳方法

Str*_*rae 12 php mysql postgresql concurrency

我有一个LAPP(linux,apache,postgresql和php)环境,但问题在Postgres或Mysql上都是一样的.

我有一个开发的cms应用程序,它处理客户端,文档(估计,发票等)和其他数据,在1个postgres DB中构建,包含许多模式(每个客户使用该应用程序一个); 让我们假设大约200个模式,每个模式同时由15个人使用(平均).

编辑:我在每个表上都有一个名为last_update的时间戳字段,以及每次更新行时更新时间戳的触发器.

情况是:

  1. People Foo和Bar正在编辑文档0001,使用包含每个文档详细信息的表单.
  2. 例如,Foo会更改货件详细信息.
  3. 栏会更改电话号码以及文档中的某些项目.
  4. Foo按"保存"按钮,应用程序更新数据库.
  5. 栏后按栏"保存"按钮,重新发送包含旧货件详细信息的表格.
  6. 在数据库中,Foo更改已丢失.

我想要的情况:

  1. People Foo,Bar,John,Mary,Paoul正在编辑文档0001,使用包含每个文档细节的表单.
  2. 例如,Foo会更改货件详细信息.
  3. 酒吧和其他人改变了别的东西.
  4. Foo按"保存"按钮,应用程序更新数据库.
  5. 酒吧和其他人得到警报'警告!这个文件已被其他人改变了.点击此处加载实际数据'.

我想知道用ajax来做这件事; 只需使用带有文档ID和最后更新时间戳的隐藏字段,每隔5秒检查最后更新的时间是否相同,什么也不做,否则,显示警告对话框.

因此,页面check-last-update.php应该类似于:

<?php
//[connect to db, postgres or mysql]
$documentId = isset($_POST['document-id']) ? $_POST['document-id'] : 0;
$lastUpdateTime = isset($_POST['last-update-time']) ? $_POST['last-update-time'] : 0;
//in the real life i sanitize the data and use prepared statements;
$qr = pg_query("
    SELECT
        last_update_time
    FROM
        documents
    WHERE
        id = '$documentId'
");
$ray = pg_fetch_assoc($qr);
if($ray['last_update_time'] > $lastUpdateTime){
    //someone else updated the document since i opened it!
    echo 'reload';
}else{
    echo 'ok';
}
?>
Run Code Online (Sandbox Code Playgroud)

但我不想每隔5秒就为每个打开一个(或多个......)文档的用户强调数据库.

那么,什么可以成为另一个没有核数据库的高效解决方案?

我想使用文件,例如为每个文档创建一个空的txt文件,每次更新文档时,我'触摸'更新'上次修改时间'的文件...但我猜这会慢一些当我有很多用户编辑同一文档时,比db和问题.

如果其他人有更好的想法或任何建议,请详细描述!

* - - - - - 更新 - - - - - *

我肯定选择不点击数据库检查"最后更新时间戳",不要介意查询是否会非常快,(主)数据库服务器还有其他任务要填满,不喜欢增加超负荷的想法.

所以,我采取这种方式:

  1. 每次某人更新文档时,我必须做一些事情来在数据库环境之外签署新的时间戳,例如,不要询问数据库.我的想法是:
    1. 文件系统:对于每个文档,我创建一个名为文档id的empry txt文件,每次文档更新时,我都会触摸该文件.我希望有成千上万的空文件.
    2. APC,php缓存:这可能比第一个更灵活,但我想知道如果在apc中永久保存成千上万的数据不会减慢php执行本身,或者消耗服务器内存.我有点害怕选择这种方式.
    3. 另一个db,sqlite或mysql(使用简单的db结构更快更轻)用于存储文档ID和时间戳.
  2. 无论我选择哪种方式(文件,apc,sub-db)我都认真考虑在子域上使用另一个web服务器(lighttp?)来处理所有那些长轮询请求.

再编辑:

文件的方式不起作用.

APC可以是解决方案.

点击数据库也可以成为解决方案,创建一个表来处理时间戳(只有两列,document_id和last_update_timestamp),这些表需要尽可能快速和轻便.

长轮询:这是我选择的方式,使用apache下的lighttpd来加载静态文件(图像,css,js等等),并且仅用于这种类型的长轮询; 这将减轻apache2的负载,特别是对于轮询.

Apache会将所有这些请求代理到lighttpd.

现在,我只需要在db解决方案和APC解决方案之间做出决定.

ps:感谢所有已经回复过我的人,你真的很有用!

Art*_*kel 3

我同意我可能不会为此访问数据库。我想我会使用 APC 缓存(或其他一些内存缓存)来维护此信息。您所描述的显然是详细记录级别的乐观锁定。数据库结构的级别越高,您需要处理的内容就越少。听起来您想检查结构中的多个表。

我将维护 ID 的缓存(在 APC 中)以及由表名键入的上次更新时间的时间戳。例如,我可能有一个表名数组,其中每个条目都以 ID 作为键,实际值是最后更新的时间戳。可能有很多方法可以使用数组或其他结构来设置它,但您已经明白了。我可能会向缓存添加超时,以便在一段时间后删除缓存中的条目 - 即,我不希望缓存增长并假设 1 天的条目不再有用)。

使用此架构,您需要执行以下操作(除了设置 APC 之外):

  • 在对任何(适用)表进行任何更新时,使用新时间戳更新 APC 缓存条目。

  • 在 ajax 中,只需“返回”至 php(获取 APC 缓存以检查条目),而不是一路“返回”数据库。