Zum Hauptinhalt springen

Was ist ein Cache?

Datenbankabfragen und Aufrufe externer APIs sind CPU- und netzwerkintensiv und können mehrere Sekunden dauern. Wenn Sie dieselben Daten wiederholt abrufen, können Sie das Ergebnis in einem Cache ablegen und nachfolgende Anfragen so deutlich beschleunigen. Laravel bietet eine einheitliche API für viele verschiedene Cache-Backends, darunter Memcached, Redis, DynamoDB und relationale Datenbanken.
Standardmäßig ist der Treiber database konfiguriert. Durch einen Wechsel zu Redis oder Memcached lässt sich der Cache noch weiter beschleunigen.

Cache konfigurieren

config/cache.php

Alle Cache-Einstellungen sind in config/cache.php gebündelt. Der Standardtreiber wird über die Umgebungsvariable CACHE_STORE gewechselt.
// config/cache.php
'default' => env('CACHE_STORE', 'database'),

Verfügbare Treiber

Speichert serialisierte Cache-Daten in einer Datenbanktabelle. Ab Laravel 11 ist die passende Migration in neuen Projekten bereits enthalten.
CACHE_STORE=database
Fehlt die Migration, erzeugen Sie sie über einen Artisan-Befehl.
php artisan make:cache-table
php artisan migrate
Speichert Cache-Daten im Dateisystem. Er benötigt keine zusätzliche Einrichtung und eignet sich für kleinere Anwendungen.
CACHE_STORE=file
Ein schneller, im Arbeitsspeicher laufender Cache-Treiber. Er wird in der Produktion am häufigsten eingesetzt und benötigt entweder die PHP-Erweiterung PhpRedis oder das Paket predis/predis.
CACHE_STORE=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
Erfordert das PECL-Paket Memcached. Konfigurieren Sie die Server in config/cache.php.
'memcached' => [
    'servers' => [
        [
            'host' => env('MEMCACHED_HOST', '127.0.0.1'),
            'port' => env('MEMCACHED_PORT', 11211),
            'weight' => 100,
        ],
    ],
],
Verwendet AWS DynamoDB als Cache-Store. Erstellen Sie vorab die DynamoDB-Tabelle und installieren Sie das AWS SDK.
composer require aws/aws-sdk-php
CACHE_STORE=dynamodb
DYNAMODB_CACHE_TABLE=cache
AWS_DEFAULT_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-key-id
AWS_SECRET_ACCESS_KEY=your-secret-key
Nutzt eine beliebige Filesystem-Disk als Key-Value-Cache-Store. Praktisch, wenn Sie eine bestehende S3-Disk direkt für den Cache verwenden möchten.
'storage' => [
    'driver' => 'storage',
    'disk' => env('CACHE_STORAGE_DISK'),
    'path' => env('CACHE_STORAGE_PATH', 'framework/cache/data'),
],
Der Treiber array ist ein In-Memory-Cache, der nur innerhalb eines Requests gültig ist. null ignoriert alle Operationen. Beide sind für automatisierte Tests nützlich.
CACHE_STORE=array

Hierarchie der Cache-Treiber

Wählen Sie den Treiber passend zu Ihrem Einsatzzweck und der gewünschten Geschwindigkeit.

Grundlegende Operationen

Die Cache-Facade beziehen

Über die Facade Cache greifen Sie auf den Cache zu.
<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;

class UserController extends Controller
{
    public function index(): array
    {
        $value = Cache::get('key');

        return [
            // ...
        ];
    }
}
Um zwischen mehreren Cache-Stores zu wählen, verwenden Sie die Methode store().
$value = Cache::store('file')->get('foo');

Cache::store('redis')->put('bar', 'baz', 600); // 10 Minuten speichern

Werte lesen: Cache::get()

Mit get() lesen Sie einen Wert aus dem Cache. Ist der Schlüssel nicht vorhanden, wird null zurückgegeben. Sie können auch einen Standardwert angeben.
$value = Cache::get('key');

// Standardwert angeben
$value = Cache::get('key', 'default');

// Standardwert per Closure verzögert ermitteln
$value = Cache::get('key', function () {
    return DB::table('settings')->get();
});

Werte speichern: Cache::put()

put() legt einen Wert im Cache ab. Der dritte Parameter ist die Gültigkeitsdauer in Sekunden.
// 10 Sekunden lang speichern
Cache::put('key', 'value', 10);

// Gültigkeit über eine Carbon-Instanz angeben
Cache::put('key', 'value', now()->plus(minutes: 10));

// Ohne Gültigkeitsdauer (dauerhaft speichern)
Cache::put('key', 'value');
Mit add() speichern Sie nur, wenn der Schlüssel noch nicht existiert.
// Nur hinzufügen, wenn nicht vorhanden (atomare Operation)
Cache::add('key', 'value', $seconds);
Für ein dauerhaftes Speichern verwenden Sie forever().
Cache::forever('key', 'value');

Lesen oder speichern: Cache::remember()

Das ist die am häufigsten verwendete Operation. Ist der Wert im Cache vorhanden, wird er zurückgegeben; andernfalls wird die Closure ausgeführt und ihr Ergebnis gespeichert.
$users = Cache::remember('users', 3600, function () {
    return DB::table('users')->get();
});
Mit Cache::remember() fassen Sie die drei Schritte „Cache prüfen → bei Cache-Miss abrufen → im Cache speichern” in einer einzigen Zeile zusammen. Ideal zum Cachen von Datenbank-Ergebnissen und Antworten externer APIs.

Ablauf von remember()

Es gibt auch rememberForever() für dauerhaftes Speichern.
$value = Cache::rememberForever('users', function () {
    return DB::table('users')->get();
});
Möchten Sie wissen, ob es ein Cache-Treffer oder ein frisch berechneter Wert war, verwenden Sie rememberWithWarmth(). Die Methode liefert ein Array mit dem Cache-Wert und einem Boolean, der angibt, ob der Wert „frisch” aus dem Cache stammt.
[$value, $warm] = Cache::rememberWithWarmth('users', 3600, function () {
    return DB::table('users')->get();
});

if ($warm) {
    // Daten stammen aus dem Cache
} else {
    // Daten wurden von der Closure neu ermittelt
}
rememberWithWarmth() eignet sich, um die Effizienz Ihres Caches zu beobachten. Ist $warm häufig false, können Sie die Gültigkeitsdauer (TTL) möglicherweise anpassen.

Stale While Revalidate (flexible Cache-Aktualisierung)

Cache::flexible() erwartet ein Array aus zwei Zeitfenstern: „frisch” und „veraltet, aber noch verwendbar”. Nutzern werden ggf. veraltete Daten zurückgegeben, während der Cache im Hintergrund aktualisiert wird.
// [Dauer als frisch (Sek.), Dauer als noch nutzbar (Sek.)]
$value = Cache::flexible('users', [5, 10], function () {
    return DB::table('users')->get();
});

Existenzprüfung: Cache::has()

if (Cache::has('key')) {
    // Verarbeitung, wenn der Cache-Eintrag existiert
}

Werte inkrementieren / dekrementieren

Sie können Zähler mit ganzzahligen Werten steuern.
// Falls nicht vorhanden, initialisieren
Cache::add('key', 0, now()->addHours(4));

// Inkrementieren / dekrementieren
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);

Lesen und löschen: Cache::pull()

Liest den Wert aus und löscht ihn anschließend aus dem Cache. Praktisch für Einmaldaten.
$value = Cache::pull('key');

Werte löschen: Cache::forget()

// Einzelnen Schlüssel löschen
Cache::forget('key');

// Gesamten Cache leeren
Cache::flush();
Cache::flush() löscht unabhängig von einem eingestellten Cache-„Präfix” alle Einträge. Wenn Sie sich einen Cache mit mehreren Anwendungen teilen, ist Vorsicht geboten.
Mit Cache::flushLocks() können Sie alle atomaren Locks im Cache entfernen.
Cache::flushLocks();

TTL verlängern: Cache::touch()

Verlängert die Gültigkeitsdauer eines bestehenden Cache-Eintrags.
// In Sekunden
Cache::touch('key', 3600);

// Mit Carbon-Instanz
Cache::touch('key', now()->addHours(2));

Cache-Memoisierung

Mit dem Treiber memo werden Cache-Zugriffe innerhalb eines einzigen Requests im Speicher zwischengespeichert. Damit vermeiden Sie überflüssige Roundtrips zum Cache-Store, wenn derselbe Schlüssel mehrfach abgefragt wird.
use Illuminate\Support\Facades\Cache;

// Standard-Store memoisieren
$value = Cache::memo()->get('key');

// Redis-Store memoisieren
$value = Cache::memo('redis')->get('key');
// Der erste Zugriff geht an den Cache-Store
$value = Cache::memo()->get('key');

// Ab dem zweiten Zugriff wird der Wert aus dem Speicher zurückgegeben (kein Store-Zugriff)
$value = Cache::memo()->get('key');

Cache-Tags

Sie können zusammengehörige Cache-Einträge über Tags gruppieren und gemeinsam löschen.
Cache-Tags stehen bei den Treibern file, dynamodb, database und storage nicht zur Verfügung. Sie erfordern redis oder memcached.

Aufbau von getaggten Caches

Ein mit mehreren Tags versehener Cache-Eintrag kann über jeden dieser Tags gemeinsam mit anderen entfernt werden.

Getaggte Werte schreiben und lesen

use Illuminate\Support\Facades\Cache;

// Mit Tags speichern
Cache::tags(['people', 'artists'])->put('John', $john, $seconds);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $seconds);

// Über die Tags lesen
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');

Getaggte Werte löschen

// Alle Einträge mit den Tags 'people' UND 'authors' löschen (löscht John und Anne)
Cache::tags(['people', 'authors'])->flush();

// Nur den Tag 'authors' löschen (nur Anne; John bleibt erhalten)
Cache::tags('authors')->flush();
Tags sind hilfreich, wenn Sie den Cache pro Gruppe – etwa pro Benutzer oder pro Beitrag – invalidieren möchten. Beispiel: Mit Cache::tags(['user', "user:{$userId}"])->flush() leeren Sie alle Cache-Einträge zu einer Benutzerin oder einem Benutzer.

Atomare Operationen (Locks)

Mit Cache::lock() implementieren Sie verteilte Locks, um Race Conditions zwischen Prozessen oder parallelen Anfragen zu vermeiden.
Dieses Feature steht bei den Cache-Treibern memcached, redis, dynamodb, database, file und array zur Verfügung. Alle Server müssen mit demselben zentralen Cache-Server kommunizieren.

Grundlegender Lock

use Illuminate\Support\Facades\Cache;

$lock = Cache::lock('foo', 10);

if ($lock->get()) {
    // Lock erfolgreich erworben (10 Sekunden gültig)

    // Exklusiv auszuführende Verarbeitung

    $lock->release();
}
Übergeben Sie eine Closure, wird der Lock nach Abschluss automatisch freigegeben.
Cache::lock('foo', 10)->get(function () {
    // Der Lock wird automatisch freigegeben
});

Auf einen Lock warten

Wartet bis zu der angegebenen Anzahl an Sekunden, bis der Lock erworben werden kann. Bei einem Timeout wird LockTimeoutException ausgelöst.
use Illuminate\Contracts\Cache\LockTimeoutException;

$lock = Cache::lock('foo', 10);

try {
    $lock->block(5); // Maximal 5 Sekunden warten

    // Verarbeitung nach Erwerb des Locks

} catch (LockTimeoutException $e) {
    // Lock konnte nicht erworben werden
} finally {
    $lock->release();
}
Mit einer Closure ist der Code kompakter.
Cache::lock('foo', 10)->block(5, function () {
    // Erwerben Sie den Lock mit bis zu 5 Sekunden Wartezeit; er wird nach Abschluss automatisch freigegeben
});

Doppelte Ausführung verhindern: withoutOverlapping()

Ein einfacher Weg, um zu verhindern, dass derselbe Prozess mehrfach parallel läuft.
Cache::withoutOverlapping('foo', function () {
    // Wird zeitgleich nur einmal ausgeführt
});

// Wartezeit und Lock-Haltezeit anpassen
Cache::withoutOverlapping('foo', function () {
    // ...
}, lockFor: 120, waitFor: 5);

Parallelität begrenzen: funnel()

Begrenzt die Anzahl gleichzeitig ausführbarer Verarbeitungen.
Cache::funnel('foo')
    ->limit(3)          // Bis zu 3 parallele Ausführungen zulassen
    ->releaseAfter(60)  // Nach 60 Sekunden automatisch freigeben
    ->block(10)         // Bis zu 10 Sekunden warten
    ->then(function () {
        // Verarbeitung, wenn ein Slot verfügbar war
    }, function () {
        // Verarbeitung, wenn kein Slot verfügbar war
    });

Locks zwischen Prozessen übergeben

Erwerben Sie einen Lock in einem Web-Request und geben Sie ihn in einem Queue-Job wieder frei.
// Lock im Request erwerben und den Job dispatchen
$lock = Cache::lock('processing', 120);

if ($lock->get()) {
    ProcessPodcast::dispatch($podcast, $lock->owner());
}

// Lock innerhalb des Queue-Jobs freigeben
Cache::restoreLock('processing', $this->owner)->release();
Um einen Lock unabhängig vom aktuellen Owner erzwungen freizugeben, verwenden Sie die Methode forceRelease.
Cache::lock('processing')->forceRelease();

Locks auffrischen

Um die Gültigkeitsdauer eines gerade gehaltenen Locks zu verlängern, verwenden Sie die Methode refresh. Ohne Angabe einer Dauer wird die ursprüngliche Gültigkeitsdauer erneut verwendet. Nützlich, wenn Sie einen kurzen Lock während einer langen Verarbeitung regelmäßig verlängern möchten, ohne von Anfang an eine sehr lange Gültigkeit setzen zu müssen.
$lock = Cache::lock('generate-reports', 60);

if ($lock->get()) {
    foreach ($reports as $report) {
        $report->generate();

        // Lock um weitere 60 Sekunden verlängern
        $lock->refresh();
    }

    $lock->release();
}

Cache-Helper

Mit der Hilfsfunktion cache() können Sie dieselben Operationen wie mit der Cache-Facade in kürzerer Form ausführen.
// Wert lesen
$value = cache('key');

// Wert mit Gültigkeitsdauer speichern
cache(['key' => 'value'], $seconds);
cache(['key' => 'value'], now()->addMinutes(10));

// Ohne Argumente die Instanz der Facade abrufen
cache()->remember('users', $seconds, function () {
    return DB::table('users')->get();
});

Praxisbeispiele

Datenbank-Ergebnisse cachen

1

Datenbank-Ergebnisse im Controller cachen

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

public function index(): array
{
    $users = Cache::remember('all-users', 3600, function () {
        return DB::table('users')->orderBy('name')->get();
    });

    return compact('users');
}
2

Cache invalidieren, wenn Daten aktualisiert werden

public function store(Request $request): RedirectResponse
{
    User::create($request->validated());

    // Cache leeren, damit die Daten beim nächsten Zugriff neu geladen werden
    Cache::forget('all-users');

    return redirect()->route('users.index');
}

Eloquent-Modelle cachen

use App\Models\Product;
use Illuminate\Support\Facades\Cache;

// Produktliste pro Kategorie 1 Stunde lang cachen
public function byCategory(int $categoryId): array
{
    $products = Cache::remember(
        "products:category:{$categoryId}",
        3600,
        fn () => Product::where('category_id', $categoryId)
            ->where('is_active', true)
            ->orderBy('name')
            ->get()
    );

    return compact('products');
}

API-Antworten cachen

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;

public function getWeather(string $city): array
{
    return Cache::remember(
        "weather:{$city}",
        1800, // 30 Minuten cachen
        function () use ($city) {
            $response = Http::get('https://api.weather.example.com/current', [
                'city' => $city,
            ]);

            return $response->json();
        }
    );
}

Gruppen-Management mit Cache-Tags

use Illuminate\Support\Facades\Cache;

class ArticleController extends Controller
{
    public function show(Article $article): array
    {
        $data = Cache::tags(['articles', "article:{$article->id}"])
            ->remember("article:{$article->id}:detail", 3600, function () use ($article) {
                return $article->load(['author', 'tags', 'comments']);
            });

        return compact('data');
    }

    public function update(Request $request, Article $article): RedirectResponse
    {
        $article->update($request->validated());

        // Alle Cache-Einträge zu diesem Artikel entfernen
        Cache::tags(["article:{$article->id}"])->flush();

        return redirect()->route('articles.show', $article);
    }
}

Zusammenfassung

MethodeBeschreibung
Cache::get('key')Wert aus dem Cache lesen
Cache::put('key', $value, $ttl)Wert im Cache speichern
Cache::remember('key', $ttl, fn)Wert lesen oder ermitteln und speichern (wichtigste Methode)
Cache::forget('key')Wert aus dem Cache entfernen
Cache::has('key')Existenz eines Cache-Eintrags prüfen
Cache::flush()Gesamten Cache leeren
Cache::forever('key', $value)Wert dauerhaft speichern
Cache::pull('key')Wert lesen und anschließend entfernen
Cache::increment('key')Zähler inkrementieren
Cache::tags([...])->flush()Getaggte Cache-Einträge löschen
  • Entwicklung / kleine Anwendungen: file oder database
  • Produktion / hohe Last: redis (in Kombination mit Laravel Horizon einfach überwachbar)
  • AWS-Umgebung: dynamodb oder storage (bei Wiederverwendung einer S3-Disk)
  • Tests: array oder null
  • Wählen Sie Cache-Schlüssel so, dass sie im gesamten Projekt eindeutig sind (z. B. users:1:profile).
  • Invalidieren Sie den Cache nach Datenänderungen mit Cache::forget() oder Cache::tags()->flush().
  • Wählen Sie die TTL angemessen – nicht zu kurz, nicht zu lang – und richten Sie sie an der Änderungsfrequenz der Daten aus.
  • Mit Cache::remember() behandeln Sie Cache-Misses besonders kompakt.
  • Verwenden Sie in der Produktion Redis und ziehen Sie eine Failover-Konfiguration in Betracht.
Zuletzt geändert am 13. Juli 2026