在app/utils/traits目录下创建optimisticlocktrait.php,代码如下:
namespace app\utils\traits;use illuminate\database\eloquent\builder;trait optimisticlocktrait{ /** * @var array $optimisticconditions * @var array $bindings */ protected $optimisticconditions, $bindings; /** * @var string $optimisticconditionraw */ protected $optimisticconditionraw; /** * save 时增加乐观锁条件 * @param builder $builder */ protected function performupdate(builder $builder) { if (!empty($this->optimisticconditions)) { foreach ($this->optimisticconditions as $field => $value) { if (is_array($value)) { $count = count($value); if ($count >= 3) { switch (strtoupper($value[1])) { case 'in': $builder->wherein($value[0], $value[2]); break; case 'not in': $builder->wherenotin($value[0], $value[2]); break; case 'between': $builder->wherebetween($value[0], $value[2]); break; case 'not between': $builder->wherenotbetween($value[0], $value[2]); break; default: $builder->where($value[0], $value[1], $value[2]); } } else { $builder->where($value); } } else { $builder->where($field, $value); } } } // 原始条件注入 if ($this->optimisticconditionraw) $builder->whereraw($this->optimisticconditionraw, $this->bindings); return $this->clearoptimistic()->performupdating($builder); } /** * updating with optimistic * * @param builder $builder * @return bool */ protected function performupdating(builder $builder) { // if the updating event returns false, we will cancel the update operation so // developers can hook validation systems into their models and cancel this // operation if the model does not pass validation. otherwise, we update. if ($this->firemodelevent('updating') === false) { return false; } // first we need to create a fresh query instance and touch the creation and // update timestamp on the model which are maintained by us for developer // convenience. then we will just continue saving the model instances. if ($this->usestimestamps()) { $this->updatetimestamps(); } // once we have run the update operation, we will fire the updated event for // this model instance. this will allow developers to hook into these after // models are updated, giving them a chance to do any special processing. $dirty = $this->getdirty(); $res = 0; if (count($dirty) > 0) { $res = $this->setkeysforsavequery($builder)->update($dirty); $this->syncchanges(); $this->firemodelevent('updated', false); } return !empty($res); } // 清除乐观锁条件 function clearoptimistic() { $this->optimisticconditions = null; $this->optimisticconditionraw = null; return $this; } // 设置乐观锁条件字段名列表 function setoptimistic(array $optimisticconditions) { $this->optimisticconditions = $optimisticconditions; return $this; } // 设置乐观锁原始条件字段名列表 function setoptimisticraw(string $optimisticconditionraw, array $bindings = []) { $this->optimisticconditionraw = $optimisticconditionraw; $this->bindings = $bindings; return $this; }}
乐观锁使用说明
1、在模型中(models)或模型父类使用
/*** app\models\basemodel* @mixin \eloquent* @method static \illuminate\database\eloquent\builder|basemodel newmodelquery()* @method static \illuminate\database\eloquent\builder|basemodel newquery()* @method static \illuminate\database\eloquent\builder|basemodel query()*/class basemodel extends model{ use optimisticlocktrait;}
2、使用方法:
$ord = order::find(1); $ord->payment_status = 1; if(!$model->setoptimistic(['payment_status' => 0]))->save()) throws new exception('订单已付过款了');
或者使用原始sql方式:
$ord = order::find(1); $ord->payment_status = 1; if(!$model->setoptimisticraw('payment_status = ?',[1]))->save()) throws new exception('订单已付过款了');
如果同一对象小涉及到多次更新,则可以清除锁条件
$ord->clearoptimistic();
以上就是乐观锁的实现方式,在实际开发中比较常用也很有必要。
推荐学习:《laravel视频教程》
以上就是laravel eloquent模型中乐观锁的实现的详细内容。
