Laravel 5.4 的 Eloquent 有个访问器功能,非常好用。
今天有个缓存需求,商品的库存 num 需要单独 redis 缓存记录(cache_num_{id}),应对并发下单,而不是直接查询数据库。且操作中一直更新这个独立缓存值,保证这个值最准确。
而且这件商品又给缓存了24小时(cache_product_{id})。
之前取商品数量的时候,需要单独去调用这个商品的对于库存缓存 cache_num_{id},比较麻烦。
想直接通过商品模型里面取出商品库存的时候,调用的是单独缓存(cache_num_{id})。
然后使用了访问器:
public function getNumAttribute($value) { $result = Cache::get('cache_num_'.$this->id); //先从缓存获取 if($result) return $result; //存在,返回独立缓存值(cache_num_{id}) return $value; //如果空值,就返回原值(原值来自 cache_product_{id} 的缓存) }
问题来了:当 num = 0 的时候,会被认为成空值,直接返回 $value 也就是主体缓存的值,此时的值并不是0。
想到错误的解决方法:
public function getNumAttribute($value) { $result = Cache::get('cache_num_'.$this->id); //先从缓存获取 if($result) return $result; //存在,返回独立缓存值(cache_num_{id}) return $this->where('id','=', $this->id)->value('num'); //重新查询数据库(造成死循环) }
一直拿不到数据库最新的数据。
郁闷了1天,才明白:调用num的时候,自动会调用 getNumAttribute()方法,会死循环。
如果调用原值就不会触发访问器,正解:
public function getNumAttribute($value) { $result = Cache::get('cache_num_'.$this->id); //先从缓存获取 if($result) return $result; //存在,返回独立缓存值(cache_num_{id}) //重新查询 $model = $this->find($this->id); $numLeft = $model->getOriginal('num'); //取原值,避免调用自己 return $numLeft ; //返回数据库最新的数据 }