[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-keshirovanie-kakie-patterny-keshirovaniya-sushchestvuyut":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":21,"progress":22,"seo":23},179,"kakie-patterny-keshirovaniya-sushchestvuyut",5,"keshirovanie","Кеширование","⚡","Какие паттерны кэширования существуют?","Паттерны кэширования — это устоявшиеся стратегии взаимодействия приложения, кэша и источника данных, определяющие кто, когда и как читает и записывает данные.\n\n### Cache-Aside (Lazy Loading)\n\nСамый распространённый паттерн. Приложение управляет кэшем явно: сначала проверяет кэш, при промахе загружает из БД и кладёт в кэш.\n\n\u003Cdetails>\u003Csummary>Пример кода\u003C\u002Fsummary>\n\n```java\npublic User getUser(Long id) {\n    \u002F\u002F 1. Проверить кэш\n    User cached = cache.get(\"user:\" + id);\n    if (cached != null) return cached;\n\n    \u002F\u002F 2. Cache miss — загрузить из БД\n    User user = userRepository.findById(id).orElseThrow();\n\n    \u002F\u002F 3. Положить в кэш\n    cache.put(\"user:\" + id, user, Duration.ofMinutes(10));\n    return user;\n}\n```\n\n```java\n\u002F\u002F Spring Cache реализует Cache-Aside автоматически\n@Cacheable(value = \"users\", key = \"#id\")\npublic User getUser(Long id) {\n    return userRepository.findById(id).orElseThrow();\n}\n```\n\n\u003C\u002Fdetails>\n\n**Плюсы:** кэшируются только запрошенные данные; промах заполняет кэш.\n**Минусы:** первый запрос всегда медленный (cold start); возможна несогласованность при обновлении БД без инвалидации кэша.\n\n### Read-Through\n\nКэш сам загружает данные из источника при промахе. Приложение всегда обращается к кэшу, не к БД напрямую.\n\n\u003Cdetails>\u003Csummary>Пример кода\u003C\u002Fsummary>\n\n```java\n\u002F\u002F Caffeine с CacheLoader — Read-Through\nLoadingCache\u003CLong, User> cache = Caffeine.newBuilder()\n    .maximumSize(10_000)\n    .expireAfterWrite(Duration.ofMinutes(10))\n    .build(id -> userRepository.findById(id).orElseThrow()); \u002F\u002F CacheLoader\n\n\u002F\u002F Использование — кэш сам вызовет loader при промахе\nUser user = cache.get(userId);\n```\n\n\u003C\u002Fdetails>\n\n**Отличие от Cache-Aside:** логика загрузки инкапсулирована в кэше, а не в сервисе.\n\n### Write-Through\n\nПри записи данные одновременно пишутся и в кэш, и в БД. Кэш всегда содержит актуальные данные.\n\n\u003Cdetails>\u003Csummary>Пример кода\u003C\u002Fsummary>\n\n```java\npublic User updateUser(Long id, UpdateRequest request) {\n    User user = userRepository.save(toEntity(request)); \u002F\u002F запись в БД\n    cache.put(\"user:\" + id, user);                      \u002F\u002F запись в кэш\n    return user;\n}\n```\n\n```java\n\u002F\u002F Spring Cache — @CachePut реализует Write-Through\n@CachePut(value = \"users\", key = \"#result.id\")\npublic User updateUser(UpdateRequest request) {\n    return userRepository.save(toEntity(request));\n}\n```\n\n\u003C\u002Fdetails>\n\n**Плюсы:** кэш всегда актуален.\n**Минусы:** каждая запись медленнее (двойная запись); кэшируются данные, которые могут никогда не быть прочитаны.\n\n### Write-Behind (Write-Back)\n\nДанные сначала пишутся в кэш, а запись в БД происходит асинхронно (с задержкой или батчами).\n\n```\nПриложение → Кэш (мгновенно) → [асинхронно, батчами] → БД\n```\n\n**Плюсы:** максимальная скорость записи; можно агрегировать множество записей в один batch.\n**Минусы:** риск потери данных при сбое кэша до синхронизации с БД.\n**Применение:** счётчики, метрики, аналитика, write-heavy нагрузка.\n\n### Refresh-Ahead\n\nКэш проактивно обновляет данные до истечения TTL для горячих ключей.\n\n```java\n\u002F\u002F Caffeine с refreshAfterWrite — автоматическое фоновое обновление\nLoadingCache\u003CLong, User> cache = Caffeine.newBuilder()\n    .maximumSize(10_000)\n    .expireAfterWrite(Duration.ofMinutes(30))     \u002F\u002F жёсткое удаление через 30 мин\n    .refreshAfterWrite(Duration.ofMinutes(10))    \u002F\u002F фоновое обновление через 10 мин\n    .build(id -> userRepository.findById(id).orElseThrow());\n\u002F\u002F Через 10 мин: возвращает старое значение + запускает фоновую загрузку нового\n\u002F\u002F Через 30 мин: ключ удаляется, следующий запрос — полный cache miss\n```\n\n**Плюсы:** нет холодных промахов для горячих данных.\n**Минусы:** сложнее в реализации; нагрузка на БД для обновления даже незапрашиваемых данных.\n\n### Сравнение паттернов\n\n| Паттерн | Кто читает из БД | Кто пишет в БД | Consistency | Latency чтения | Latency записи |\n|---------|-----------------|----------------|-------------|----------------|----------------|\n| Cache-Aside | Приложение | Приложение | Eventual | Miss — медленно | Без кэша |\n| Read-Through | Кэш | Приложение | Eventual | Miss — медленно | Без кэша |\n| Write-Through | Кэш | Кэш + БД синхронно | Strong | Hit — быстро | Медленнее (2 записи) |\n| Write-Behind | Кэш | Кэш, затем БД асинхронно | Eventual | Быстро | Быстро |\n| Refresh-Ahead | Кэш (проактивно) | Приложение | Eventual | Всегда быстро | Без кэша |\n\n### Выводы\n\n- **Cache-Aside + TTL** — самый распространённый и простой паттерн; Spring `@Cacheable` реализует его\n- **Write-Through** — когда нужна согласованность кэша с БД; Spring `@CachePut`\n- **Write-Behind** — для write-heavy нагрузок (счётчики, логи)\n- **Refresh-Ahead** — для данных, которые должны быть всегда теплыми (каталог товаров, курсы валют)\n\n### Частые ошибки\n\n- **Cache-Aside без инвалидации** — обновили БД, забыли обновить\u002Fудалить кэш, получили stale data\n- **Write-Through для редко читаемых данных** — кэш заполняется данными, которые никто не читает\n- **Write-Behind без обработки ошибок** — если асинхронная запись в БД упала, данные потеряны\n- **Путать паттерны** — Cache-Aside + `@CachePut` = рабочая комбинация; Read-Through в Spring — через Caffeine `LoadingCache`\n\n### Как используется в 2026\n\n- Cache-Aside — 80%+ всех кэширований в Spring-приложениях\n- Write-Behind — используется в Redis Streams и Apache Kafka для буферизации записей\n- Caffeine `refreshAfterWrite` — стандарт для проактивного обновления справочных данных\n\n> **На собеседовании:** интервьюер проверяет, понимаете ли вы разницу между паттернами и умеете ли выбрать нужный под задачу. Частая ошибка — описать только Cache-Aside и не знать Write-Behind и Refresh-Ahead.","","middle",[15,16,17,18,19,20],"read-through","write-through","patterns","caching","cache-aside","write-behind",[],null,{"title":24,"description":25,"ogTitle":26,"ogDescription":27,"keywords":28,"schemaAnswer":38,"featuredSnippetReady":39},"Какие паттерны кэширования существуют — Gymterview","Обзор паттернов кэширования: Cache-Aside, Read-Through, Write-Through, Write-Behind, Refresh-Ahead. Сравнение, примеры кода на Java и Spring Cache.","Паттерны кэширования: Cache-Aside, Read-Through, Write-Through и другие — Gymterview","Разбираем 5 паттернов кэширования с примерами на Java и Spring. Сравнение consistency, latency и применимости.",[29,30,31,32,33,34,35,36,37],"паттерны кэширования","Cache-Aside","Read-Through","Write-Through","Write-Behind","Refresh-Ahead","Spring Cache","Cacheable","Java","Основные паттерны: Cache-Aside (приложение явно управляет кэшем, самый распространённый), Read-Through (кэш сам загружает при промахе), Write-Through (запись одновременно в кэш и БД), Write-Behind (запись в кэш, асинхронная синхронизация с БД), Refresh-Ahead (проактивное обновление до истечения TTL). Cache-Aside используется в 80%+ Spring-приложений через @Cacheable.",true]