Laravel封装乐观锁保存方法

文章目录

前言
# 实现 主要点
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 = "已确认"
代码
namespace App\Models\Auth;

use App\Models\Traits\RichSoftDeletes;
use DateTimeInterface;

/**
 * Class User
 * @package App\Models\Auth
 * @property string $password
 * @property string $creator
 */
class User extends \Illuminate\Database\Eloquent\Model
{

    use RichSoftDeletes;

    protected $fillable = ['name', 'mobile', 'password', 'creator', 'updater'];

    protected $hidden = ['mobile'];

    protected $casts = [
        'id' => 'string',
    ];

    public static function booted()
    {
        static::optimisticSaving(function ($model) {

        });

        static::updating(function ($model) {

        });

        static::optimisticSaved(function ($model) {

        });
    }

    # before 事件
    public static function optimisticSaving($callback)
    {
        static::registerModelEvent('optimisticSaving', $callback);
    }

    # after 事件
    public static function optimisticSaved($callback)
    {
        static::registerModelEvent('optimisticSaved', $callback);
    }


    public function optimisticSave()
    {
        if ($this->fireModelEvent('optimisticSaving') === false) {
            return false;
        }

        $change = $this->getDirty();

        # 没有变动就不操作数据库了
        if (!$change) return true;

        # 如果使用记录修改时间,那么将修改时间添加变动中
        # 这里也希望将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)) throw new \Exception(implode(',', $diff) . '字段应该查询出来');

        # 如果变动的字段在老数据之中,则以老的数据作为锁
        $where = [];
        $fields = array_intersect($originalField, $changeField);
        foreach ($fields as $field) {
            $where[$field] = $original[$field];
        }

        if ($this->fireModelEvent('updating') === false) {
            return false;
        }

        $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;
    }
}
使用
同 model->save()基本一致
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值