Skip to content

furkankayam/spring-boot-cqrs-example

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ Spring Boot CQRS Example

Project Architecture

JaCoCo Coverage Report
  • βœ… CQRS (Command Query Responsibility Segregation) pattern implementation for modern e-commerce systems.

Used Technologies in The Project:

Java Spring Boot PostgreSQL Elasticsearch RabbitMQ Gradle Docker


πŸ“š What is CQRS?

CQRS = Separate Write and Read operations!

Traditional Approach:

User β†’ API β†’ Single Database (PostgreSQL)
        ↓
   Write & Read (Slow!)

CQRS Approach:

User β†’ API β†’ Command (Write) β†’ PostgreSQL
           β†’ Query (Read)    β†’ Elasticsearch (Fast!)

🎯 Why CQRS?

Real World Scenario:

In an e-commerce site:

  • πŸ›’ Product purchase: 10% (LOW)
  • πŸ‘€ Product viewing: 90% (HIGH)

Problem:

  • You're both writing and reading from PostgreSQL
  • Millions of users searching products simultaneously β†’ SLOWNESS!

Solution: CQRS

  • Write (Command) β†’ PostgreSQL (Strong, ACID)
  • Read (Query) β†’ Elasticsearch (Fast, Search)

🎬 Scenario: Product System

πŸ“ Command Side (Write - 10%)

User β†’ "Add new product" 
     β†’ Command API
     β†’ Save to PostgreSQL
     β†’ Send event to RabbitMQ

Endpoint:

POST /api/commands/products
Content-Type: application/json

{
  "name": "iPhone 15 Pro",
  "price": 45000.0
}

πŸ“– Query Side (Read - 90%)

User β†’ "Search iPhone"
     β†’ Query API  
     β†’ Fetch from Elasticsearch (⚑ Fast!)

Endpoint:

GET /api/products?name=iPhone

πŸ”„ Event Flow

  1. Admin adds new product

    • Written to PostgreSQL
  2. RabbitMQ publishes event

    • ProductCreatedEvent
  3. Listener catches event

    • Written to Elasticsearch
  4. Users search quickly

    • Read from Elasticsearch

πŸ› οΈ Technologies

Technology Purpose Why?
PostgreSQL Write Database ACID, reliable writes
Elasticsearch Read Database Fast search, full-text search
RabbitMQ Event Bus Asynchronous communication
Spring Boot Framework Rapid development

πŸš€ Setup

1️⃣ Start Services with Docker Compose

docker-compose up -d

Database Configuration

  • PostgreSQL
    • URL: http://localhost:5432
    • Database: cqrs_example
    • Username: postgres
    • Password: postgres

  • Elasticsearch
    • URL: http://localhost:9200
    • Username: elastic
    • Password: elasticsearch

  • RabbitMQ Management
    • URL: http://localhost:15672
    • Username: rabbitmq
    • Password: rabbitmq

2️⃣ Run the Application

./gradlew bootRun

3️⃣ Test It

Create product:

curl -X POST http://localhost:8080/api/commands/products \
  -H "Content-Type: application/json" \
  -d '{"name":"Laptop","price":15000.0}'

List products:

curl http://localhost:8080/api/products

πŸ“‚ Project Structure

src/main/java/com/furkankayam/
β”œβ”€β”€ command/                            # πŸ“ WRITE side
β”‚   β”œβ”€β”€ Product.java                    # JPA Entity
β”‚   β”œβ”€β”€ ProductCommandRepository.java
β”‚   β”œβ”€β”€ ProductCommandService.java
β”‚   └── ProductCommandController.java
β”‚
β”œβ”€β”€ query/                              # πŸ“– READ side  
β”‚   β”œβ”€β”€ ProductDocument.java            # Elasticsearch Document
β”‚   β”œβ”€β”€ ProductQueryRepository.java
β”‚   β”œβ”€β”€ ProductQueryService.java
β”‚   └── ProductQueryController.java
β”‚
β”œβ”€β”€ event/                              # πŸ”„ Events
β”‚   β”œβ”€β”€ ProductEvent.java
β”‚   β”œβ”€β”€ ProductEventPublisher.java
β”‚   └── ProductEventListener.java
β”‚
β”œβ”€β”€ dto/                                # πŸ“¦ Data Transfer Objects
β”‚   β”œβ”€β”€ request/
β”‚   β”‚   β”œβ”€β”€ CreateProductRequest.java
β”‚   β”‚   └── UpdateProductRequest.java
β”‚   └── response/
β”‚       └── ProductResponse.java
β”‚
└── config/                             # βš™οΈ Configuration
    └── RabbitMQConfig.java

🎯 API Endpoints

Command API (Write)

POST   /api/commands/products      # Create product
PUT    /api/commands/products/{id} # Update product
DELETE /api/commands/products/{id} # Delete product

Query API (Read)

GET /api/products                              # All products
GET /api/products/{id}                         # Product by ID
GET /api/products/search?name=...              # Search by name
GET /api/products/search/price?min=...&max=... # Search by price

πŸ”₯ Real World Example

❌ Without CQRS:

1000 users searching "iPhone" simultaneously
  └─> PostgreSQL JOIN queries
  └─> Slow! (500ms - 2s)
  └─> Database locked!

βœ… With CQRS:

1000 users searching "iPhone" simultaneously
  └─> Elasticsearch full-text search
  └─> Fast! (10ms - 50ms)
  └─> PostgreSQL unaffected!

πŸ“Š Performance Comparison

Operation Traditional CQRS
Create product 50ms 50ms
Search product 800ms 20ms
1000 users searching DB locked Working smoothly

πŸ€” When to Use CQRS?

βœ… Use:

  • Unbalanced read/write ratio (90% reads, 10% writes)
  • High traffic
  • Complex search requirements
  • E-commerce, blogs, news sites

❌ Don't Use:

  • Simple CRUD applications
  • Low traffic
  • Balanced read/write operations

License

This project is licensed under the MIT License. See the LICENSE file for details

Created by Mehmet Furkan KAYA

About

πŸ”€ Simple Spring Boot CQRS with PostgreSQL, Elasticsearch, and RabbitMQ

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages