On update, only flush the updated model from the cache - not all of them
leenooks opened this issue · 4 comments
Hi,
Is it possible to just flush the "updated" model from the cache, instead of all models (of the same type)?
IE: If I have a model "Foo" and I query from the DB id 1 and id 2, then a subsequent query for id 1 or id 2 should result in the data come from the cache. However, if I update id 1, and have have $flushCacheOnUpdate=TRUE set, then both id 1 and id 2 are flushed from the cache.
I would like just id 1 to be flushed, so that the next query for that ID retrieves the data from the DB (with the updates).
Setting $flushCacheOnUpdate
will invalidate the entire caching. Instead, you might want to do a manual flush.
- You might do manual invalidation:
$user1 = User::cacheFor(60)->cacheTags(['id:1'])->find(1);
$user2 = User::cacheFor(60)->cacheTags(['id:2'])->find(2);
$user1->update(['name' => 'John']);
User::flushQueryCache(['id:1']);
- If you still want to use
$flushCacheOnUpdate = true;
, update the tags that will get flushed upon updates:
class User {
/**
* Invalidate the cache automatically
* upon update in the database.
*
* @var bool
*/
protected static $flushCacheOnUpdate = true;
/**
* Set the base cache tags that will be present
* on all queries.
*
* @return array
*/
protected function getCacheBaseTags(): array
{
return [
"id:{$this->id}",
];
}
}
$user1 = User::cacheFor(60)->cacheTags(['id:1'])->find(1);
$user2 = User::cacheFor(60)->cacheTags(['id:2'])->find(2);
$user1->update(['name' => 'John']);
// Cache flushed successfully only for user 1
So I've been trying the second method - but I'm not using the ->cacheTags() in the query.
IE: If I have
$o = Import::find($this->argument('arg'));
$o->active = ! $o->active;
$o->save();
$this->info('Changed active to :'.($o->active ? 'ON' : 'OFF'));
dump(['now'=>Import::find($this->argument('arg'))->active ? 'ON' : 'OFF']);
I only ever get:
Changed active to :ON
array:1 [
"now" => "OFF"
]
So the only way to achieve it is if I have cacheTags()
in the original query? (IE: It cannot automatically do it just using getCacheBaseTags()
) ?
This package caches the queries, not the models.
I'm not sure I follow - but...
One of the attractive attributes of this library is that caching is added with minimal change to existing code. (Hence why I dont use cacheTags()
yet in my queries.)
So I tried this:
getCacheBaseTags()
on the Model is as you have it.
Then,
$cachetag = sprintf('%s:%d','id',$this->argument('arg'));
$o = Import::cacheTag($cachetag)->find($this->argument('arg'));
$o->active = ! $o->active;
$o->save();
$this->info('Changed active to :'.($o->active ? 'ON' : 'OFF'));
dump(['now'=>Import::find($this->argument('arg'))->active ? 'ON' : 'OFF']);
(Notice in the final query I have not added the cacheTag()
. So while the DB is updated correctly, any subsequent queries not using the cacheTag() id yields a static stale record :( )
I think the answer is yes - but I have to use cacheTag()
consistently if I want to expire only changed records from the cache (of the same model), and still have my queries return the correct (cached) record?
(I do a large import of 10,000's records of multiple models - and the DB is remote, so I was planning on using a local redis cache to reduce some of the latency to the DB, where I do some queries to validate some records before I create/update a record. So during the import, I dont want to expire unchanged records.)