Course topics

By WebNest Studio Engineering Team

Spring Framework Tutorial

Spring Data Fundamentals

Writing data-access code by hand — opening connections, building SQL, mapping result sets to objects — is repetitive and error-prone. Spring Data eliminates most of this boilerplate by letting you define a Java interface describing the operations you need, and having Spring generate a working implementation automatically at runtime, based purely on the interface's method names and generic type parameters.

The core building blocks are CrudRepository, which provides basic create/read/update/delete operations, and JpaRepository (part of Spring Data JPA), which extends CrudRepository with JPA-specific and pagination/sorting capabilities. You simply declare an interface extending one of these, parameterized by your entity type and its ID type, and Spring Data supplies the implementation without you writing a single line of SQL for common operations.

CrudRepository — the Base Contract

CrudRepository<T, ID> defines generic methods like save(entity), findById(id), findAll(), count(), and deleteById(id). Any interface extending it, annotated with the entity and its ID type, immediately gets working implementations of all of these methods — Spring Data generates a proxy class at startup that implements the interface against the configured data store.

JpaRepository — JPA-Specific Extensions

JpaRepository<T, ID> extends both CrudRepository and PagingAndSortingRepository, adding JPA-specific conveniences like saveAndFlush() (immediately synchronizing changes to the database rather than waiting for the persistence context to flush later) and batch-oriented methods. Its inherited pagination support (findAll(Pageable pageable)) is essential for any endpoint returning large result sets in pages rather than all at once.

Derived Query Methods

Spring Data can generate a query just from a method's name, following a naming convention it parses at startup. A method named findByLastNameAndAgeGreaterThan(String lastName, int age) is automatically translated into the equivalent query, with no implementation code required. For cases the naming convention can't express cleanly, the @Query annotation lets you write a JPQL (or native SQL) query explicitly on the method.

  • findBy... — generates a SELECT query filtered by the named fields.
  • countBy... / existsBy... — generate COUNT/EXISTS queries with the same field-matching convention.
  • deleteBy... — generates a DELETE query matching the named fields.
  • @Query("SELECT u FROM User u WHERE u.email = :email") — an explicit JPQL query for cases the naming convention can't express.

Example

A JpaRepository interface with a derived query method

Java
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;

import java.util.List;

@Entity
class Customer {
    @Id
    Long id;
    String lastName;
    int age;
}

interface CustomerRepository extends JpaRepository<Customer, Long> {
    // No implementation needed — Spring Data generates the query from the method name.
    List<Customer> findByLastNameAndAgeGreaterThan(String lastName, int age);
}

@Service
class CustomerService {
    private final CustomerRepository repository;
    CustomerService(CustomerRepository repository) { this.repository = repository; }

    List<Customer> findAdultsNamed(String lastName) {
        return repository.findByLastNameAndAgeGreaterThan(lastName, 18);
    }
}
// Assuming the database contains customers with lastName "Sharma" aged 15, 22, and 30
Output
findAdultsNamed("Sharma") returns a List<Customer> containing the two customers aged 22 and 30, generated SQL: SELECT * FROM customer WHERE last_name = ? AND age > ?

Common Mistakes

  • Misspelling a field name in a derived query method (e.g. "findByLastnam" instead of "findByLastName"), causing a startup failure because Spring Data cannot match it to an entity property.
  • Assuming CrudRepository provides pagination out of the box — pagination and sorting require extending PagingAndSortingRepository or JpaRepository instead.
  • Writing overly long, hard-to-read derived method names for complex queries instead of switching to an explicit @Query for clarity.
  • Calling saveAndFlush() habitually instead of save(), unnecessarily forcing a database round-trip on every call when the default flush timing would have been fine.

Exercise

Using the lesson's A JpaRepository interface with a derived query method example, create a small implementation or design sketch that demonstrates Spring Data generates a working repository implementation from an interface, with no manual DAO code required.. Add a test case or scenario that would catch Misspelling a field name in a derived query method (e.g. "findByLastnam" instead of "findByLastName"), causing a startup failure because Spring Data cannot match it to an entity property., and describe the expected result.

Show hints
  • Start with CrudRepository — the Base Contract and compare your approach with A JpaRepository interface with a derived query method. Identify the decision or behavior the lesson recommends.
  • Walk through your scenario step by step. Confirm that it follows Spring Data generates a working repository implementation from an interface, with no manual DAO code required. and that it would catch the failure described by Misspelling a field name in a derived query method (e.g. "findByLastnam" instead of "findByLastName"), causing a startup failure because Spring Data cannot match it to an entity property..

Quick quiz

1. Which choice is a mistake to avoid in Spring Data Fundamentals?

  • A. Assuming CrudRepository provides pagination out of the box — pagination and sorting require extending PagingAndSortingRepository or JpaRepository instead.
  • B. Spring Data generates a working repository implementation from an interface, with no manual DAO code required.
  • C. Misspelling a field name in a derived query method (e.g. "findByLastnam" instead of "findByLastName"), causing a startup failure because Spring Data cannot match it to an entity property.
Show answer

C. Avoid this approach: Misspelling a field name in a derived query method (e.g. "findByLastnam" instead of "findByLastName"), causing a startup failure because Spring Data cannot match it to an entity property. The lesson recommends: Spring Data generates a working repository implementation from an interface, with no manual DAO code required.

Interview questions

A teammate is about to make this mistake: Misspelling a field name in a derived query method (e.g. "findByLastnam" instead of "findByLastName"), causing a startup failure because Spring Data cannot match it to an entity property. How would you diagnose and correct it using the lesson's guidance?

Show answer

Spring Data generates a working repository implementation from an interface, with no manual DAO code required. Apply this in CrudRepository — the Base Contract; the example A JpaRepository interface with a derived query method shows one way to do it. Avoid Misspelling a field name in a derived query method (e.g. "findByLastnam" instead of "findByLastName"), causing a startup failure because Spring Data cannot match it to an entity property. and explain how your implementation or design prevents that failure.

Key Points to Remember

  • Spring Data generates a working repository implementation from an interface, with no manual DAO code required.
  • CrudRepository provides basic CRUD operations; JpaRepository adds JPA-specific features plus pagination and sorting.
  • Derived query methods are generated purely from a method's name following Spring Data's naming convention.
  • @Query lets you write explicit JPQL/native SQL when a query cannot be cleanly expressed as a method name.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering