> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Cache

> Erfahren Sie, wie Sie mit dem Cache-System von Laravel die Performance Ihrer Anwendung verbessern.

## 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.

<Info>
  Standardmäßig ist der Treiber `database` konfiguriert. Durch einen Wechsel zu Redis oder Memcached lässt sich der Cache noch weiter beschleunigen.
</Info>

## Cache konfigurieren

### config/cache.php

Alle Cache-Einstellungen sind in `config/cache.php` gebündelt.
Der Standardtreiber wird über die Umgebungsvariable `CACHE_STORE` gewechselt.

```php theme={null}
// config/cache.php
'default' => env('CACHE_STORE', 'database'),
```

### Verfügbare Treiber

<AccordionGroup>
  <Accordion title="database (Standard)">
    Speichert serialisierte Cache-Daten in einer Datenbanktabelle.
    Ab Laravel 11 ist die passende Migration in neuen Projekten bereits enthalten.

    ```ini theme={null}
    CACHE_STORE=database
    ```

    Fehlt die Migration, erzeugen Sie sie über einen Artisan-Befehl.

    ```shell theme={null}
    php artisan make:cache-table
    php artisan migrate
    ```
  </Accordion>

  <Accordion title="file">
    Speichert Cache-Daten im Dateisystem.
    Er benötigt keine zusätzliche Einrichtung und eignet sich für kleinere Anwendungen.

    ```ini theme={null}
    CACHE_STORE=file
    ```
  </Accordion>

  <Accordion title="redis">
    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`.

    ```ini theme={null}
    CACHE_STORE=redis
    REDIS_HOST=127.0.0.1
    REDIS_PORT=6379
    ```
  </Accordion>

  <Accordion title="memcached">
    Erfordert das PECL-Paket Memcached.
    Konfigurieren Sie die Server in `config/cache.php`.

    ```php theme={null}
    'memcached' => [
        'servers' => [
            [
                'host' => env('MEMCACHED_HOST', '127.0.0.1'),
                'port' => env('MEMCACHED_PORT', 11211),
                'weight' => 100,
            ],
        ],
    ],
    ```
  </Accordion>

  <Accordion title="dynamodb">
    Verwendet AWS DynamoDB als Cache-Store.
    Erstellen Sie vorab die DynamoDB-Tabelle und installieren Sie das AWS SDK.

    ```shell theme={null}
    composer require aws/aws-sdk-php
    ```

    ```ini theme={null}
    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
    ```
  </Accordion>

  <Accordion title="storage">
    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.

    ```php theme={null}
    'storage' => [
        'driver' => 'storage',
        'disk' => env('CACHE_STORAGE_DISK'),
        'path' => env('CACHE_STORAGE_PATH', 'framework/cache/data'),
    ],
    ```
  </Accordion>

  <Accordion title="array / null (für Tests)">
    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.

    ```ini theme={null}
    CACHE_STORE=array
    ```
  </Accordion>
</AccordionGroup>

### Hierarchie der Cache-Treiber

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

```mermaid theme={null}
flowchart LR
    A["Anwendung"] --> B["Cache-Facade"]

    subgraph L1 ["L1: pro Request (am schnellsten)"]
        C["array<br>für Tests / Entwicklung"]
        D["memo (Wrapper)<br>reduziert wiederholte Zugriffe"]
    end

    subgraph L2 ["L2: In-Memory (schnell)"]
        E["Redis<br>Empfehlung für Produktion"]
        F["Memcached<br>verteilter Cache"]
    end

    subgraph L3 ["L3: persistenter Speicher (Standard)"]
        G["database (Standard)"]
        H["file"]
        I["DynamoDB (AWS)"]
        J["storage<br>Disks wie S3"]
    end

    B --> C
    B --> D
    B --> E
    B --> F
    B --> G
    B --> H
    B --> I
    B --> J
```

## Grundlegende Operationen

### Die Cache-Facade beziehen

Über die Facade `Cache` greifen Sie auf den Cache zu.

```php theme={null}
<?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()`.

```php theme={null}
$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.

```php theme={null}
$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.

```php theme={null}
// 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.

```php theme={null}
// Nur hinzufügen, wenn nicht vorhanden (atomare Operation)
Cache::add('key', 'value', $seconds);
```

Für ein dauerhaftes Speichern verwenden Sie `forever()`.

```php theme={null}
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.

```php theme={null}
$users = Cache::remember('users', 3600, function () {
    return DB::table('users')->get();
});
```

<Tip>
  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.
</Tip>

### Ablauf von remember()

```mermaid theme={null}
flowchart TD
    A["Cache::remember('key', $ttl, fn)"] --> B{"Existiert 'key'<br>im Cache-Store?"}
    B -->|"Treffer (Hit)"| C["Wert aus dem Cache lesen"]
    B -->|"Fehltreffer (Miss)"| D["Closure fn ausführen<br>z. B. DB-Query / API-Aufruf"]
    D --> E["Ergebnis im Cache speichern<br>Gültigkeit = $ttl Sekunden"]
    E --> F["Wert zurückgeben"]
    C --> F
```

Es gibt auch `rememberForever()` für dauerhaftes Speichern.

```php theme={null}
$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.

```php theme={null}
[$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
}
```

<Tip>
  `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.
</Tip>

#### 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.

```php theme={null}
// [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()`

```php theme={null}
if (Cache::has('key')) {
    // Verarbeitung, wenn der Cache-Eintrag existiert
}
```

### Werte inkrementieren / dekrementieren

Sie können Zähler mit ganzzahligen Werten steuern.

```php theme={null}
// 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.

```php theme={null}
$value = Cache::pull('key');
```

### Werte löschen: `Cache::forget()`

```php theme={null}
// Einzelnen Schlüssel löschen
Cache::forget('key');

// Gesamten Cache leeren
Cache::flush();
```

<Warning>
  `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.
</Warning>

Mit `Cache::flushLocks()` können Sie alle atomaren Locks im Cache entfernen.

```php theme={null}
Cache::flushLocks();
```

### TTL verlängern: `Cache::touch()`

Verlängert die Gültigkeitsdauer eines bestehenden Cache-Eintrags.

```php theme={null}
// 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.

```php theme={null}
use Illuminate\Support\Facades\Cache;

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

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

```php theme={null}
// 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.

<Warning>
  Cache-Tags stehen bei den Treibern `file`, `dynamodb`, `database` und `storage` nicht zur Verfügung. Sie erfordern `redis` oder `memcached`.
</Warning>

### Aufbau von getaggten Caches

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

```mermaid theme={null}
flowchart TD
    A["Cache::tags(['people', 'artists'])<br>.put('John', $data)"] --> B["Cache für John"]
    C["Cache::tags(['people', 'authors'])<br>.put('Anne', $data)"] --> D["Cache für Anne"]

    B --> T1["Tag: people"]
    B --> T2["Tag: artists"]
    D --> T1
    D --> T3["Tag: authors"]

    T1 -->|"flush()"| E["John und Anne löschen"]
    T2 -->|"flush()"| F["nur John löschen"]
    T3 -->|"flush()"| G["nur Anne löschen"]
```

### Getaggte Werte schreiben und lesen

```php theme={null}
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

```php theme={null}
// 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();
```

<Tip>
  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.
</Tip>

## Atomare Operationen (Locks)

Mit `Cache::lock()` implementieren Sie verteilte Locks, um Race Conditions zwischen Prozessen oder parallelen Anfragen zu vermeiden.

<Info>
  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.
</Info>

### Grundlegender Lock

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
// 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`.

```php theme={null}
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.

```php theme={null}
$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.

```php theme={null}
// 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

<Steps>
  <Step title="Datenbank-Ergebnisse im Controller cachen">
    ```php theme={null}
    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');
    }
    ```
  </Step>

  <Step title="Cache invalidieren, wenn Daten aktualisiert werden">
    ```php theme={null}
    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');
    }
    ```
  </Step>
</Steps>

### Eloquent-Modelle cachen

```php theme={null}
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

```php theme={null}
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

```php theme={null}
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

<AccordionGroup>
  <Accordion title="Häufig genutzte Methoden">
    | Methode                            | Beschreibung                                                 |
    | ---------------------------------- | ------------------------------------------------------------ |
    | `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                              |
  </Accordion>

  <Accordion title="Wahl des Treibers">
    * **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`
  </Accordion>

  <Accordion title="Best Practices">
    * 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.
  </Accordion>
</AccordionGroup>


## Related topics

- [Laravel Pulse](/de/pulse.md)
- [Upgrade-Anleitung von Laravel 12 auf 13](/de/blog/upgrade-12-to-13.md)
- [MongoDB](/de/mongodb.md)
- [Passwort zurücksetzen](/de/passwords.md)
- [Laravel Octane](/de/octane.md)
