You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决页面/标签页关闭时无法可靠解锁数据库条目编辑锁的问题?

解决单用户编辑锁定的可靠方案

我完全懂你现在的头疼点——用beforeunload触发AJAX解锁确实不靠谱,浏览器关闭或标签页关掉时,这个事件要么直接不触发,要么AJAX请求还没跑完页面就被销毁了,结果条目被无限锁死,只能手动去数据库改,太影响体验了。下面给你几个更可靠的替代方案,都是实际项目里验证过的:

方案1:心跳轮询+自动超时兜底(最易实现)

这个思路是让前端定时给后端发"心跳",告诉后端"我还在编辑这个条目";后端记录每个锁定条目的最后心跳时间,一旦超过设定的超时时间(比如5分钟)没收到心跳,就自动解锁。

具体步骤:

  1. 数据库修改:给devices表新增一个last_heartbeat字段(datetime类型),用来记录最后一次心跳的时间。
  2. 前端逻辑调整:页面锁定条目后,启动定时器每隔1分钟发送一次心跳请求;页面卸载时尝试主动解锁,同时清除定时器。
  3. 后端定时清理:用Cron任务(或类似定时工具)定期检查所有锁定的条目,超时的自动解锁。

前端代码示例:

$(document).ready(function() {
    var locked = <?=json_encode($data['in-review']);?>;
    var uid = $("#uidfield").val();
    let heartbeatTimer;

    if(locked) {
        // 禁用表单元素,和之前逻辑一致
        $('input, #delete-model-button, #uidfield, #submitbutton').attr('disabled', true);
        $('#submitbutton').text("This model is in review by another reviewer.");
    } else {
        // 先锁定条目
        $.ajax({
            url: 'process/in-review.php',
            type: 'POST',
            data: {uid: uid, value: 1},
            success: function () {
                console.log("Model Locked in Review");
                // 启动心跳:每分钟发一次请求更新心跳时间
                heartbeatTimer = setInterval(() => {
                    $.ajax({
                        url: 'process/heartbeat.php',
                        type: 'POST',
                        data: {uid: uid},
                        error: () => console.error("Heartbeat failed - check your connection")
                    });
                }, 60000);
            }
        });

        // 页面卸载时:清除定时器+尝试主动解锁(即使失败,心跳停了后端会自动处理)
        $(window).on('beforeunload', function() {
            clearInterval(heartbeatTimer);
            // 这里把AJAX设为同步,尽量让浏览器等请求完成(部分浏览器支持)
            $.ajax({
                url: 'process/in-review.php',
                type: 'POST',
                async: false,
                data: {uid: uid, value: 0}
            });
        });
    }
});

后端心跳接口(heartbeat.php):

<?php
include('db.php');
$uid = $_POST['uid'];
// 只更新当前锁定条目的心跳时间
$db->run("UPDATE `devices` SET `last_heartbeat`=NOW() WHERE `uid`=? AND `in-review`=1", [$uid]);
?>

定时清理脚本(cleanup-locks.php):

<?php
include('db.php');
// 超过5分钟没心跳,自动解锁
$db->run("UPDATE `devices` SET `in-review`=0 WHERE `in-review`=1 AND `last_heartbeat` < DATE_SUB(NOW(), INTERVAL 5 MINUTE)");
?>

Cron任务配置(Linux服务器):

每天每分钟执行一次清理脚本,确保超时锁及时释放:

* * * * * php /path/to/your/project/process/cleanup-locks.php

方案2:WebSocket实时监听连接状态(最实时)

如果你的项目可以引入WebSocket(比如用PHP的Ratchet框架或Node.js的Socket.IO),这个方案可靠性最高——用户关闭页面时,WebSocket连接会立刻断开,服务器能实时解锁对应条目,完全不需要依赖前端事件。

核心逻辑:

  1. 后端搭建WebSocket服务器,维护一个条目ID => 用户连接的映射表。
  2. 用户打开页面时,通过WebSocket发送锁定请求,服务器检查条目是否已被锁定,未锁定则标记并记录连接。
  3. 当WebSocket连接断开(用户关闭页面/标签页),服务器自动解锁对应条目。

这个方案实时性拉满,但需要额外搭建WebSocket服务,适合对体验要求高的场景。

方案3:数据库层面的超时锁兜底(最小改动)

如果不想大幅修改前端,也可以在数据库层面做优化,让旧锁自动失效:

具体步骤:

  1. 给devices表新增locked_at(datetime)和locked_by(用户ID/会话ID)字段。
  2. 用户锁定条目时,不仅设置in-review=1,还要记录当前时间和锁定者ID。
  3. 其他用户尝试锁定时,检查现有锁是否超时(比如超过5分钟),超时则允许覆盖旧锁。

修改后的in-review.php:

<?php
include('db.php');
session_start();
$uid = $_POST['uid'];
$value = $_POST['value'];
$currentUser = $_SESSION['user_id']; // 假设你有用户会话

if($value == 1) {
    // 检查是否有有效的锁
    $existingLock = $db->run("SELECT `locked_at`, `locked_by` FROM `devices` WHERE `uid`=? AND `in-review`=1", [$uid])->fetch();
    
    if($existingLock && strtotime($existingLock['locked_at']) > strtotime('-5 minutes')) {
        // 锁有效,返回失败
        echo json_encode(['success' => false, 'msg' => 'Model is locked by another user']);
        exit;
    }
    // 锁无效/不存在,执行锁定
    $db->run("UPDATE `devices` SET `in-review`=1, `locked_at`=NOW(), `locked_by`=? WHERE `uid`=?", [$currentUser, $uid]);
    echo json_encode(['success' => true]);
} else {
    // 只有锁定者才能解锁
    $db->run("UPDATE `devices` SET `in-review`=0, `locked_at`=NULL, `locked_by`=NULL WHERE `uid`=? AND `locked_by`=?", [$uid, $currentUser]);
    echo json_encode(['success' => true]);
}
?>

方案对比:

  • 方案1:实现简单,兼容性强,适合大多数场景,是最推荐的选择。
  • 方案2:实时性最高,但需要额外的WebSocket服务成本。
  • 方案3:改动最小,适合快速修复现有问题,但实时性稍差。

内容的提问来源于stack exchange,提问作者GrumpyCrouton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:23:54