Home/Learn/Spring Boot/JpaRepository & CrudRepository

JpaRepository & CrudRepository

Beginner
Data Access

JpaRepository extends PagingAndSortingRepository adding flush, batch-delete, and JPA-specific bulk operations on top of basic CRUD.

Overview

Spring Data JPA provides a repository abstraction that eliminates boilerplate DAO code. The hierarchy is: Repository → CrudRepository (basic CRUD) → PagingAndSortingRepository (pagination + sorting) → JpaRepository (adds flush, saveAllAndFlush, deleteAllInBatch, and findAll(Sort)). In practice, most Spring Boot applications extend JpaRepository which gives all capabilities. Spring Data generates the implementation at runtime — you write only the interface. Custom query methods are derived from method names, @Query annotations, or Specifications for dynamic queries.

Repository hierarchy and core methods

JpaRepository<T, ID> provides: save(entity), saveAll(entities), findById(id), findAll(), findAllById(ids), existsById(id), count(), delete(entity), deleteById(id), deleteAll(), findAll(Sort), findAll(Pageable), flush(), saveAllAndFlush(), deleteAllInBatch(). The T is the entity type and ID is the primary key type.

Java — JpaRepository definition and core method usage
// Define repository — Spring generates the implementation
public interface OrderRepository extends JpaRepository<Order, Long> {
    // All JpaRepository methods available immediately:
    // save, findById, findAll, delete, count, existsById, ...
}

// Usage in service
@Service
@Transactional(readOnly = true)
public class OrderService {

    private final OrderRepository orderRepository;

    public Optional<Order> findById(Long id) {
        return orderRepository.findById(id);       // returns Optional — no NPE
    }

    public List<Order> findAll() {
        return orderRepository.findAll();
    }

    @Transactional
    public Order save(Order order) {
        return orderRepository.save(order);        // INSERT or UPDATE (merge)
    }

    @Transactional
    public void delete(Long id) {
        orderRepository.deleteById(id);
    }

    public long count() {
        return orderRepository.count();
    }

    // Batch operations — much faster than N individual deletes
    @Transactional
    public void deleteAll(List<Order> orders) {
        orderRepository.deleteAllInBatch(orders);  // single DELETE ... WHERE id IN (...)
    }
}

Derived query methods by method name

Spring Data parses method names and generates JPQL automatically. Keywords: findBy, countBy, existsBy, deleteBy; conditions: And, Or, Between, LessThan, GreaterThan, Like, Containing, StartingWith, EndingWith, In, NotNull, IsNull, OrderBy. Method names can get verbose — use @Query for complex conditions.

Java — derived query methods covering common patterns
public interface OrderRepository extends JpaRepository<Order, Long> {

    // Simple field lookup
    List<Order> findByStatus(OrderStatus status);
    List<Order> findByCustomerId(Long customerId);

    // Combined conditions
    List<Order> findByStatusAndCreatedAtAfter(OrderStatus status, LocalDateTime date);

    // Collection parameter
    List<Order> findByStatusIn(List<OrderStatus> statuses);

    // Null / not null
    List<Order> findByShippedAtIsNull();
    List<Order> findByShippedAtIsNotNull();

    // Comparison
    List<Order> findByTotalGreaterThan(BigDecimal amount);
    List<Order> findByTotalBetween(BigDecimal min, BigDecimal max);

    // Count / exists
    long countByStatus(OrderStatus status);
    boolean existsByCustomerIdAndStatus(Long customerId, OrderStatus status);

    // Delete (requires @Transactional on calling method)
    void deleteByCreatedAtBefore(LocalDateTime cutoff);

    // Sorted
    List<Order> findByStatusOrderByCreatedAtDesc(OrderStatus status);

    // Pageable result
    Page<Order> findByCustomerId(Long customerId, Pageable pageable);
}

Projections and DTO queries

Fetching full entities when you only need a few fields wastes memory and serialisation overhead. Spring Data supports interface projections (closed projections map fields exactly) and class-based DTO projections (constructor expression). Projections only SELECT the needed columns, reducing database load.

Java — interface and DTO projections for lean data fetching
// Interface projection — Spring generates a proxy
public interface OrderSummary {
    Long getId();
    OrderStatus getStatus();
    BigDecimal getTotal();
    // Only id, status, total are SELECTed — not all columns
}

// DTO projection — class with matching constructor
public record OrderDTO(Long id, String customerName, BigDecimal total) {}

public interface OrderRepository extends JpaRepository<Order, Long> {

    // Interface projection
    List<OrderSummary> findByStatus(OrderStatus status);

    // DTO projection — JPQL constructor expression
    @Query("SELECT new com.example.OrderDTO(o.id, c.name, o.total) " +
           "FROM Order o JOIN o.customer c " +
           "WHERE o.status = :status")
    List<OrderDTO> findOrderDTOsByStatus(@Param("status") OrderStatus status);

    // Dynamic projection — caller chooses what to project
    <T> List<T> findByCustomerId(Long customerId, Class<T> type);
}

// Usage:
List<OrderSummary> summaries = repo.findByStatus(PENDING);
List<OrderDTO> dtos = repo.findByCustomerId(42L, OrderDTO.class);

Key Points to Remember

  • 1Extend JpaRepository<Entity, Id> — Spring generates the implementation at runtime with no code required
  • 2save() performs INSERT for new entities (no id) and UPDATE (merge) for managed/detached entities
  • 3deleteAllInBatch() issues a single DELETE ... WHERE id IN (...) — much faster than N individual deleteById calls
  • 4Derived method names generate JPQL automatically; use @Query for complex conditions to keep method names short
  • 5Always use readOnly = true on @Transactional for query-only methods — reduces overhead and enables Hibernate optimisations
  • 6Interface projections SELECT only specified columns; DTO projections (constructor expression) work for multi-table queries

Interview Questions

Sign in to ask Aria
1

What is the difference between CrudRepository, JpaRepository, and PagingAndSortingRepository?

EasyInfosys
2

What does save() do differently for a new entity vs a detached entity?

MediumThoughtworks
3

How would you fetch only id and status from an orders table without loading the full entity?

MediumAmazon
4

Why is deleteAllInBatch() preferred over calling deleteById() in a loop?

EasyWipro
5

How does Spring Data generate SQL from method names like findByStatusAndCreatedAtAfter?

MediumGoogle

Ask Aria about JpaRepository & CrudRepository

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…