[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-arkhitektura-prilozheniy-chto-takoe-cqrs-command-query-responsibility-segregation":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":19,"progress":20,"seo":21},129,"chto-takoe-cqrs-command-query-responsibility-segregation",3,"arkhitektura-prilozheniy","Архитектура приложений","🏗️","Что такое CQRS (Command Query Responsibility Segregation)","CQRS — паттерн, разделяющий операции чтения (Query) и записи (Command) на отдельные модели. Это похоже на организацию банка: одно окно принимает заявления (command), другое — выдаёт справки (query), и у каждого свой оптимизированный процесс.\n\nВ классической архитектуре одна и та же модель используется и для записи, и для чтения. CQRS разделяет их, позволяя оптимизировать каждую сторону независимо.\n\n### Схема\n\n```\n              ┌──────────────────────────────────┐\n              │            API Gateway           │\n              └────────┬────────────┬────────────┘\n                       │            │\n                Command│            │Query\n                       ▼            ▼\n              ┌──────────┐  ┌──────────────┐\n              │ Command  │  │   Query      │\n              │ Model    │  │   Model      │\n              │ (Write)  │  │   (Read)     │\n              └────┬─────┘  └──────┬───────┘\n                   │               │\n                   ▼               ▼\n              ┌──────────┐  ┌──────────────┐\n              │  Write   │  │   Read DB    │\n              │  DB      │──▶  (денормал.) │\n              │(PostgreSQL)│ │  (Redis \u002F   │\n              └──────────┘  │  Elasticsearch)│\n                  синхронизация └────────────┘\n                  через события\n```\n\n### Пример кода\n\n\u003Cdetails>\u003Csummary>Пример кода\u003C\u002Fsummary>\n\n```java\n\u002F\u002F Command — изменяет состояние, ничего не возвращает\npublic interface CreatePaymentCommandHandler {\n    void handle(CreatePaymentCommand command);\n}\n\n@Service\npublic class CreatePaymentCommandHandlerImpl implements CreatePaymentCommandHandler {\n\n    private final PaymentWriteRepository repository;\n    private final EventPublisher eventPublisher;\n\n    @Override\n    @Transactional\n    public void handle(CreatePaymentCommand command) {\n        Payment payment = Payment.create(command);\n        repository.save(payment);\n        eventPublisher.publish(new PaymentCreatedEvent(payment));\n    }\n}\n\n\u002F\u002F Query — только читает, не изменяет состояние\npublic interface PaymentQueryService {\n    PaymentView findById(Long id);\n    List\u003CPaymentView> findByClientId(Long clientId);\n}\n\n@Service\npublic class PaymentQueryServiceImpl implements PaymentQueryService {\n\n    private final PaymentReadRepository readRepository;  \u002F\u002F оптимизирован для чтения\n\n    @Override\n    public PaymentView findById(Long id) {\n        return readRepository.findById(id);\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n### Когда применять CQRS\n\n- Нагрузка на чтение значительно превышает нагрузку на запись (типично для банковских систем: просмотр выписок vs. совершение платежей).\n- Модели для чтения и записи сильно отличаются.\n- Нужна независимая масштабируемость чтения и записи.\n- Система использует Event Sourcing.\n\n### Когда не стоит применять\n\n- Простые CRUD-приложения.\n- Когда eventual consistency неприемлема.\n- Маленькие проекты с одной командой.\n\n### Связь с Event Sourcing\n\nCQRS часто комбинируют с Event Sourcing — вместо хранения текущего состояния хранится полная последовательность событий, из которых состояние можно восстановить. Это даёт полный аудит изменений и возможность «перемотки» состояния на любой момент времени, но значительно усложняет реализацию.\n\n> **На собеседовании:** Интервьюер хочет услышать, когда CQRS оправдан, а когда это overengineering. Частая ошибка — считать, что CQRS всегда требует двух баз данных; на деле можно начать с разделения моделей в одной БД.","","senior",[15,16,17,18],"cqrs","patterns","event-sourcing","architecture",[],null,{"title":22,"description":23,"ogTitle":22,"ogDescription":24,"keywords":25,"schemaAnswer":31,"featuredSnippetReady":32},"CQRS (Command Query Responsibility Segregation) — Gymterview","CQRS — паттерн, разделяющий операции чтения и записи на отдельные модели. Когда применять, примеры на Java, связь с Event Sourcing.","CQRS — паттерн, разделяющий операции чтения (Query) и записи (Command) на отдельные модели.",[26,27,28,29,30],"CQRS","Command Query Responsibility Segregation","разделение чтения и записи","Event Sourcing","паттерн CQRS","CQRS — паттерн, разделяющий операции чтения (Query) и записи (Command) на отдельные модели, позволяя оптимизировать каждую сторону независимо. Command изменяет состояние и ничего не возвращает, Query только читает. Применяется когда нагрузка на чтение превышает запись, модели для чтения и записи сильно отличаются, или нужна независимая масштабируемость. Часто комбинируется с Event Sourcing. Не стоит применять для простых CRUD-приложений и когда eventual consistency неприемлема.",true]