# 实现 主要点1.参考model->save() 方法
2.对比改动前后数据差异确定以那些数据作为锁进行比较
3.model changes,original数据的同步
4.增加自己的模型事件
5.模型事件的触发
# 方法的作用(即乐观锁作用)# 以推送用友场景为例# 查询订单状态为已确认的推送到用友select * from goods where status ="已确认" limit 10# foreach result# 修改数据状态# 如果推送标记前退款了,这条语句还是能执行成功,造成了先退款了也能推送到用友的风险
update goods set push_status ="推送中" where id="id"
推送操作...
update goods set push_status ="推送完成" where id="id"# 使用乐观锁解决问题
update goods set push_status ="推送中" where id="id" and status ="已确认"
代码
namespaceApp\Models\Auth;useApp\Models\Traits\RichSoftDeletes;useDateTimeInterface;/**
* Class User
* @package App\Models\Auth
* @property string $password
* @property string $creator
*/classUserextends\Illuminate\Database\Eloquent\Model{useRichSoftDeletes;protected$fillable=['name','mobile','password','creator','updater'];protected$hidden=['mobile'];protected$casts=['id'=>'string',];publicstaticfunctionbooted(){static::optimisticSaving(function($model){});static::updating(function($model){});static::optimisticSaved(function($model){});}# before 事件publicstaticfunctionoptimisticSaving($callback){static::registerModelEvent('optimisticSaving',$callback);}# after 事件publicstaticfunctionoptimisticSaved($callback){static::registerModelEvent('optimisticSaved',$callback);}publicfunctionoptimisticSave(){if($this->fireModelEvent('optimisticSaving')===false){returnfalse;}$change=$this->getDirty();# 没有变动就不操作数据库了if(!$change)returntrue;# 如果使用记录修改时间,那么将修改时间添加变动中# 这里也希望将updated_at 作为锁进行比较if($this->usesTimestamps()){$this->updateTimestamps();# 这里的change比上面的change多了一个updated_at$change=$this->getDirty();}# 修改之前查询到的数据(老数据)$original=$this->getOriginal();$changeField=array_keys($change);$originalField=array_keys($original);# 修改的数据必须有老的数据对比做为锁,没有则提示它$diff=array_diff($changeField,$originalField);if(!empty($diff))thrownew\Exception(implode(',',$diff).'字段应该查询出来');# 如果变动的字段在老数据之中,则以老的数据作为锁$where=[];$fields=array_intersect($originalField,$changeField);foreach($fieldsas$field){$where[$field]=$original[$field];}if($this->fireModelEvent('updating')===false){returnfalse;}$query=$this->newModelQuery();$saved=(bool)$this->setKeysForSaveQuery($query)->where($where)->update($change);# 同步changes属性$this->syncChanges();$this->fireModelEvent('updated',false);if($saved){$this->fireModelEvent('optimisticSaved',false);# 同步Original$this->syncOriginal();}return$saved;}}