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

Yii2中基于Optimistic Locking的更新操作代码调试求助

Yii2 乐观锁更新操作问题修复方案

问题分析

你的实现存在几个关键问题导致乐观锁未生效或不符合预期:

  1. 数据库表缺失version字段:乐观锁依赖该字段存储版本号,必须确保records表存在对应字段。
  2. Controller异常处理不完整:捕获StaleObjectException后未返回视图,会导致页面空白。
  3. 视图隐藏字段写法不够规范:未使用ActiveForm标准方式生成版本号隐藏字段。
  4. Model行为配置可更清晰:显式配置版本字段属性,避免歧义。

修复步骤与代码

1. 确保数据库表存在version字段

执行SQL添加字段:

ALTER TABLE `records` ADD COLUMN `version` INT NOT NULL DEFAULT 0;

2. 优化Model代码

<?php

namespace app\models;

use yii\behaviors\OptimisticLockBehavior;
use yii\db\ActiveRecord;

class RecordModel extends ActiveRecord
{
    public static function tableName()
    {
        return 'records';
    }

    public function behaviors()
    {
        return array_merge(parent::behaviors(), [
            [
                'class' => OptimisticLockBehavior::class,
                'versionAttribute' => 'version', // 显式指定版本字段,逻辑更清晰
            ],
        ]);
    }

    // 添加验证规则,确保字段合法性
    public function rules()
    {
        return [
            [['text'], 'required'],
            [['version'], 'integer'],
        ];
    }
}

3. 修复Controller代码(补全异常处理逻辑)

<?php

namespace app\controllers;

use Yii;
use app\models\RecordModel;
use yii\db\StaleObjectException;
use yii\web\NotFoundHttpException;

class RecordController extends AppController
{
    public function actionUpdate($id = 1)
    {
        $model = RecordModel::findOne($id);
        if (!$model) {
            throw new NotFoundHttpException('指定记录不存在');
        }

        try {
            if ($model->load(Yii::$app->request->post()) && $model->save()) {
                Yii::$app->session->setFlash('success', '更新成功');
                return $this->refresh();
            }
        } catch (StaleObjectException $e) {
            Yii::$app->session->setFlash('error', '该记录已被其他用户修改,请刷新页面后重试');
            // 重新获取最新版本的模型,避免用户继续使用旧数据提交
            $model = RecordModel::findOne($id);
        }

        // 统一返回视图,覆盖加载失败、异常捕获等所有场景
        return $this->render('update', [
            'model' => $model,
        ]);
    }
}

4. 优化View代码

<h1>更新待办记录</h1>
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>

<?php if(Yii::$app->session->hasFlash('success')): ?>
    <div class="alert alert-success alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
            <span aria-hidden="true">&times;</span>
        </button>
        <?= Yii::$app->session->getFlash('success') ?>
    </div>
<?php endif; ?>

<?php if(Yii::$app->session->hasFlash('error')): ?>
    <div class="alert alert-danger alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
            <span aria-hidden="true">&times;</span>
        </button>
        <?= Yii::$app->session->getFlash('error') ?>
    </div>
<?php endif; ?>

<?php $form = ActiveForm::begin();?>
<?= $form->field($model, 'text')->label('待办内容') ?>
<?= $form->field($model, 'version')->hiddenInput()->label(false) ?>

<?= Html::submitButton('保存修改', ['class' => 'btn btn-success']) ?>
<?php ActiveForm::end();?>

测试验证

  1. 打开两个浏览器窗口,同时加载同一记录的更新页面。
  2. 在第一个窗口修改内容并提交,成功更新后version字段会自动自增。
  3. 在第二个窗口提交修改,此时会触发乐观锁异常,页面显示错误提示并加载最新的记录版本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 00:25:09