Yii2中基于Optimistic Locking的更新操作代码调试求助
Yii2 乐观锁更新操作问题修复方案
问题分析
你的实现存在几个关键问题导致乐观锁未生效或不符合预期:
- 数据库表缺失
version字段:乐观锁依赖该字段存储版本号,必须确保records表存在对应字段。 - Controller异常处理不完整:捕获
StaleObjectException后未返回视图,会导致页面空白。 - 视图隐藏字段写法不够规范:未使用ActiveForm标准方式生成版本号隐藏字段。
- 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">×</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">×</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();?>
测试验证
- 打开两个浏览器窗口,同时加载同一记录的更新页面。
- 在第一个窗口修改内容并提交,成功更新后
version字段会自动自增。 - 在第二个窗口提交修改,此时会触发乐观锁异常,页面显示错误提示并加载最新的记录版本。
内容的提问来源于stack exchange,提问作者Azizxon Zufarov
相关产品推荐
相关产品推荐

