Skip to content

Expert · Spring Boot basics · topic 55 of 60 · 30 min

JPA and Spring Data repositories

Explanation

JPA (Jakarta Persistence) maps Java classes to database tables, and Hibernate is the usual implementation. An @Entity class with an @Id becomes a table; Spring Data JPA turns an interface extending JpaRepository into a working repository with save, findById and findAll, and generates queries from method names like findByCityAndPriceLessThan. Watch out for lazy loading and the N+1 query problem.

Why an ORM?

Writing JDBC code for every table means mapping every column to every field by hand. An ORM (object-relational mapper) does that mapping for you: you work with Java objects, and it generates the SQL. JPA is the standard specification (package jakarta.persistence in Spring Boot 3 and later; older projects used javax.persistence), and Hibernate is the most common implementation.

java
import jakarta.persistence.*;

@Entity
@Table(name = "product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)   // the database generates the id
    private Long id;

    @Column(nullable = false, length = 120)
    private String name;

    private String city;
    private long pricePaise;
    private boolean inStock;

    protected Product() { }                               // JPA needs a no-arg constructor
    public Product(String name, String city, long pricePaise) { this.name = name; this.city = city; this.pricePaise = pricePaise; this.inStock = true; }
    // getters …
}

Spring Data repositories

java
public interface ProductRepository extends JpaRepository<Product, Long> {

    List<Product> findByCity(String city);                                   // derived query
    List<Product> findByCityAndPricePaiseLessThan(String city, long max);
    Optional<Product> findFirstByNameIgnoreCase(String name);
    long countByInStockFalse();

    @Query("select p from Product p where p.inStock = true order by p.pricePaise desc")
    List<Product> findAvailableMostExpensiveFirst();                         // JPQL (uses class and field names)
}

// Spring generates the implementation at start-up:
productRepository.save(new Product("Steel bottle", "Pune", 34_900));
productRepository.findById(1L);          // Optional<Product>
productRepository.findAll();
productRepository.deleteById(1L);

Spring Data reads method names such as findByCityAndPricePaiseLessThan and builds the query: WHERE city = ? AND price_paise < ?. You can run the equivalent SQL in the tasks below.

Relationships (in brief)

java
@Entity
public class Customer {
    @Id @GeneratedValue private Long id;
    private String name;
    @OneToMany(mappedBy = "customer")
    private List<Order> orders = new ArrayList<>();
}

@Entity
@Table(name = "orders")                       // "order" is a reserved SQL word
public class Order {
    @Id @GeneratedValue private Long id;
    @ManyToOne(fetch = FetchType.LAZY)        // many orders belong to one customer
    private Customer customer;
    private long amountPaise;
}

Lazy loading and the N+1 problem

Lazy relationships are loaded only when you first access them. Loading 100 customers and then calling customer.getOrders() for each one fires 1 query for the customers plus 100 queries for their orders: the N+1 problem, a very common cause of slow APIs. Fix it by fetching what you need in one query (a JOIN FETCH in @Query, or an @EntityGraph) or by querying DTOs directly.

java
@Query("select c from Customer c left join fetch c.orders where c.city = :city")
List<Customer> findWithOrdersByCity(@Param("city") String city);   // one query instead of N+1

Transactions

Put @Transactional on service methods that change data. Inside a transaction, entities loaded through JPA are "managed": changing a field is written to the database automatically at commit (dirty checking), even without calling save. Turn on SQL logging (spring.jpa.show-sql=true, or logging the org.hibernate.SQL category) during development to see what queries really run.

Careful: Never use spring.jpa.hibernate.ddl-auto=update or create-drop against a production database: Hibernate may alter or drop tables. Manage schema changes with migration tools such as Flyway or Liquibase, reviewed like code. And remember that derived query names are checked at start-up: a typo like findByCitty fails the application start, which is good.
Think of it like this: JPA is like a translator who sits between you (speaking Java objects) and the database (speaking SQL tables). Spring Data is a secretary who drafts standard letters from your one-line request ("find by city"). The N+1 problem is sending the secretary to the archive 101 times instead of asking for one combined file.
Tip: Learn SQL well even when using JPA. When performance problems come, you will read the generated SQL, add indexes and sometimes write the query yourself.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

JPA and Spring Data repositories · 1/6

JPA and Spring Data

In this lesson you will store data with JPA and Spring Data repositories.

Prefer a video by a teacher? Find free videos on “spring data jpa tutorial entity jparepository derived queries n+1 problem” on YouTube ↗

In real life: Store-wise product search

A retail chain's tablet app lets staff search products available in their city under a price limit. The repository method findByCityAndPricePaiseLessThanAndInStockTrue generates exactly the SQL below, and an index on (city, price_paise) keeps it fast.

sql
SELECT id, name, price_paise FROM product
WHERE city = 'Pune' AND price_paise < 100000 AND in_stock = TRUE;

Practice (0/3 done)

Task 1 · Code · SQL

Write the SQL that Spring Data generates for findByCity("Pune") on the product table, selecting the name column only, sorted by name.

Task 2 · Code · SQL

Write the SQL for findByCityAndPriceLessThanAndInStockTrue("Pune", 1000): names of in-stock products in Pune that cost less than 1000 (in_stock is 1 for true).

Task 3 · Question

You load 50 customers and then call getOrders() on each (lazy). How many SQL queries run, typically?

Quick quiz

Question 1

1.Which package do JPA annotations come from in Spring Boot 3 and later?

Question 2

2.What does JpaRepository<Product, Long> mean?

Question 3

3.What is the N+1 problem?

Question 4

4.Which is the safe way to change a production database schema?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which package do JPA annotations come from in Spring Boot 3 and later?

Answer: jakarta.persistence

The move to Jakarta EE renamed the packages.

What does JpaRepository<Product, Long> mean?

Answer: A repository for Product entities whose id type is Long

Entity type and ID type.

What is the N+1 problem?

Answer: Running one query for a list plus one extra query per item

Common with lazy relationships.

Which is the safe way to change a production database schema?

Answer: Reviewed migration scripts with Flyway or Liquibase

Migrations are versioned and reviewed.

A page loads 30 posts, then runs one query per post to get its author. How many queries is that?Related

Answer: 31

1 query for the posts plus 30 for the authors: 31. This is the N+1 problem.

From ORMs: working with databases from code

Which query is safe from SQL injection?Related

Answer: FromSql($"SELECT * FROM Users WHERE Name = {name}")

FromSql with interpolation turns the value into a parameter.

From Entity Framework Core: databases with C#

Which test annotation loads only the web layer for controller tests?Related

Answer: @WebMvcTest

@WebMvcTest is a test slice for MVC controllers.

From Layers: controller, service and repository

What is the minimum Java version for Spring Boot 3?Related

Answer: Java 17

Spring Boot 3 requires Java 17+.

From Creating a Spring Boot app

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Spring Boot basics”. The module exam comes next.
  2. Module 11 exam: Spring Boot basics · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Design patterns, JVM internals and interviews. 60 topics left in the course before the final exam.

← Previous: Layers: controller, service and repository