Fluent Cache
Here are some examples for how we can use cache with database and why should we.
Table of contents
No headings in the article.
During the development of production apps, it is important to ensure that our server remains highly responsive. Some queries consistently yield the same result set from the database, leading to unnecessary overhead costs and time consumption each time these queries are executed.
To address this, we can optimize the server's performance by caching these queries. By storing the results on the server, we can eliminate the need to repeatedly access the database and retrieve the identical dataset.
To achieve this in Laravel there are a couple of different ways. The first is to write a raw query and cache it.
public function getUsers()
{
$cacheTimeInSeconds = 86400;
$query = "SELECT id, name from users where name LIKE '%Samuel%'";
$usersResponse = Cache::remember(
'users',
$cacheTimeInSeconds,
function () use ($query) {
return DB::select($query);
}
);
}
In this case, the variable $cacheTimeInSeconds represents the duration in seconds before the cache is refreshed. The second parameter, 'users', serves as the keyword used to save, fetch, or delete the specific cache. The third parameter is a callback function that returns the result set obtained from the database.
This method involves generating a cache within the application to store the result set inside storage > framework > cache > data
directory.
Another approach is to utilize the eloquent model for database querying.
public function getUsers()
{
// initialize cacheTimeInSeconds ...
$name = request()->get('name'); // "Samuel"
$usersResponse = Cache::remember(
'users',
$cacheTimeInSeconds,
function () use ($name) {
return User::where('name', 'LIKE', "%$name%")->get();
}
);
}
In certain scenarios, there may be a use case where you need to retrieve multiple datasets from a single function. This typically occurs when applying filters and passing different parameters. In that case, we'll extract the SQL and make it the key identifier or in other words the first parameter for the Cache::remember
method. In this way, every query sentence will serve as the identifier for its cached data set.
public function filterUsers()
{
$name = request()->get('name'); // "Samuel"
$email = request()->get('email'); // "samuel@xyz.com"
$users = new User();
if($name){
$users = $users->where("name", "LIKE", "%$name%");
}
if($email){
$users = $users->where("email", "LIKE", "%$email%");
}
$sql = $users->toSql();
$sql = $this->replaceSearchStringWithBindings(
'?',
$users->getBindings(),
$sql
);
$usersResponse = Cache::remember(
$sql,
$cacheTimeInSeconds,
function () use ($sql) {
return DB::select($sql);
}
);
return $usersResponse;
}
As a result of toSql()
method the returned SQL query will contain the question mark ?
where ever we have passed some query parameter. Here the method str_replace_first
will do its job (which is defined below) to replace every ?
in the query with the bindings one by one. As a result, we can have the proper SQL query we can use as both (query to fetch the result set from the database and the key identifier to cache that result set).
private function replaceSearchStringWithBindings(
$search, $bindings, $subject
) {
$search = '/'.preg_quote($search, '/').'/';
foreach ($bindings as $binding) {
// replace first occurrence of search string
$subject = preg_replace($search, $binding, $subject, 1);
}
return $subject;
}
There are some other things to remember about cache but we'll talk about that in the next blog.
Peace...