laravel的Eloquent非常好用,可以自动维护created_at和updated_at两个字段,但是实际场景中可能同一个请求中更新多张表,而created_at时间不一致的情况
例如:
//foo表新增数据Foo::query()->create();//假装耗时操作...sleep(3);//bar表中新增数据Bar::query()->create();
结果foo表和bar表的created_at相差3秒
那么这种问题如何解决呢,
laravel的每个包扩展性都非常强,如果能找到Eloquent源码中维护created_at字段的方法,就不必在上层处理。
在Illuminate\Database\Eloquent\Model中可以看到使用了HasTimestamps这个trait来时间时间戳,
abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable{use Concerns\HasAttributes,Concerns\HasEvents,Concerns\HasGlobalScopes,Concerns\HasRelationships,Concerns\HasTimestamps,//处理自动维护时间戳Concerns\HidesAttributes,Concerns\GuardsAttributes,ForwardsCalls;......
那么继续,
在Illuminate\Database\Eloquent\Concern\HasTimestamps中找到
/*** Update the creation and update timestamps.** @return void*/protected function updateTimestamps(){$time = $this->freshTimestamp();//获取时间戳if (! is_null(static::UPDATED_AT) && ! $this->isDirty(static::UPDATED_AT)) {$this->setUpdatedAt($time);}if (! $this->exists && ! is_null(static::CREATED_AT) &&! $this->isDirty(static::CREATED_AT)) {$this->setCreatedAt($time);}}
/*** Get a fresh timestamp for the model.** @return \Illuminate\Support\Carbon*/public function freshTimestamp(){return Date::now();//就是这里了}
那么只要重写这个方法就好了,所以定义个一个trait
这里使用了变量容器,相关参考laravel技巧—变量容器
namespace App\Model;use App\Light\Box\Box;use App\Light\Box\BoxContainer;trait KpHasTimestamps{public function freshTimestamp(){//获取当前请求时间戳常量return Box::get(BoxContainer::NOW);//变量容器}}
在模型Foo中使用KpHasTimestamps
namespace App\Model;use Illuminate\Database\Eloquent\Model;class Foo extends Model{//使用新定义维护时间戳的方法use KpHasTimestamps;protected $primaryKey = 'id';protected $table = 'foo';protected $guarded = [];}
在模型Bar中也使用KpHasTimestamps
namespace App\Model;use Illuminate\Database\Eloquent\Model;class Bar extends Model{//使用新定义维护时间戳的方法use KpHasTimestamps;protected $primaryKey = 'id';protected $table = 'bar';protected $guarded = [];}
现在再执行最开始的两条create代码,查看表中created_at时间一致了。
