Real World Example

Where This Fits

Most Indian product companies (Flipkart, Paytm, Zerodha, Razorpay) run Spring Boot services on MySQL or PostgreSQL, with H2 or Testcontainers in tests. The pattern is the same as below: entity + repository + service, with config per environment.

ShopEase: Product CRUD on MySQL

@Service
@Transactional
public class ProductService {
    private final ProductRepository repo;
    private final ProductMapper mapper;

    public ProductService(ProductRepository repo, ProductMapper mapper) {
        this.repo = repo;
        this.mapper = mapper;
    }

    @Transactional(readOnly = true)
    public Page<ProductResponse> search(String q, Pageable pageable) {
        Page<Product> page = (q == null || q.isBlank())
                ? repo.findAll(pageable)
                : repo.findByNameContainingIgnoreCase(q, pageable);
        return page.map(mapper::toResponse);
    }

    public ProductResponse create(CreateProductRequest req) {
        if (repo.existsBySku(req.sku())) throw new DuplicateSkuException(req.sku());
        return mapper.toResponse(repo.save(mapper.toEntity(req)));
    }
}

@GetMapping
public Page<ProductResponse> search(@RequestParam(required = false) String q,
                                    @PageableDefault(size = 20, sort = "name") Pageable pageable) {
    return service.search(q, pageable);
}

Example

Create, then search with paging and sorting. The data is now really stored in MySQL and survives a restart:

curl -X POST localhost:8080/api/products -H "Content-Type: application/json" -d '{"sku":"ELE-1002","name":"Wireless Keyboard","description":"Hindi + English keys","price":1299.00,"stock":60,"category":"Electronics"}'
curl "localhost:8080/api/products?q=wireless&page=0&size=2&sort=price,desc"

Example output

{"id":3,"sku":"ELE-1002","name":"Wireless Keyboard","description":"Hindi + English keys","price":1299.00,"stock":60,"category":"Electronics","inStock":true}
{"content":[{"id":3,"sku":"ELE-1002","name":"Wireless Keyboard","description":"Hindi + English keys","price":1299.00,"stock":60,"category":"Electronics","inStock":true},{"id":1,"sku":"ELE-1001","name":"Wireless Mouse","description":"2.4 GHz, silent clicks","price":799.00,"stock":120,"category":"Electronics","inStock":true}],"page":{"size":2,"number":0,"totalElements":2,"totalPages":1}}

What Hibernate sent to MySQL (with show-sql: true):

Hibernate: select count(*)>0 from products p1_0 where p1_0.sku=?
Hibernate: insert into products (category,description,name,price,sku,stock) values (?,?,?,?,?,?)
Hibernate: select p1_0.id,p1_0.category,p1_0.description,p1_0.name,p1_0.price,p1_0.sku,p1_0.stock from products p1_0 where upper(p1_0.name) like upper(?) escape '\' order by p1_0.price desc limit ?,?

Note: The "page" object is the stable JSON format for Page in Spring Data 3.3+ (enable it with @EnableSpringDataWebSupport(pageSerializationMode = VIA_DTO)). Returning your own page DTO is also a good choice.