CrudRepository in Spring Data JPA
Fast recall
Quick revision
Core answer
Whether you understand the repository abstraction and that Spring auto-generates the implementation from a plain interface — no DAO code written by hand
Writing a CustomerRepositoryImpl class by hand (causing a bean conflict), confusing CrudRepository with JpaRepository, or assuming findAll returns a List
Mention runtime proxy generation backed by SimpleJpaRepository, the Optional return of findById that forces null-safety, and the Iterable (not List) return of findAll
Interview-ready guide
Interview answer
For example, interface CustomerRepository extends CrudRepository<Customer, Long> inherits save, findById, findAll, count, existsById, delete, and deleteById. customerRepository.findById(42L).orElseThrow(...) handles absence explicitly. If callers need paging, sorting, or JPA-specific batch methods, use the appropriate richer repository interface rather than converting an unbounded Iterable after loading it.
CrudRepository in Spring Data JPA
Direct Answer
CrudRepository<T, ID> is Spring Data's basic repository interface for saving, finding, checking, counting, and deleting aggregates. Its exact return collection types and behavior come from the current Spring Data version. findById returns Optional<T>. save chooses new-entity persistence or merge through the store module; it is not a direct promise that every non-null id becomes one SQL UPDATE.
Code Example
// Spring Boot 3.2 + Java 17
@Entity
@Table(name = "customers")
public class Customer {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// getters/setters
}
// No implementation needed — Spring generates it at runtime
public interface CustomerRepository extends CrudRepository<Customer, Long> { }
@Service
public class CustomerService {
private final CustomerRepository repository;
CustomerService(CustomerRepository r) { this.repository = r; }
public Customer create(String name, String email) {
var c = new Customer();
c.setName(name);
c.setEmail(email);
return repository.save(c); // INSERT (id was null)
}
public Optional<Customer> get(Long id) {
return repository.findById(id); // SELECT by PK -> Optional
}
public long total() {
return repository.count(); // SELECT COUNT(*)
}
public void remove(Long id) {
repository.deleteById(id); // DELETE
}
}
You wrote zero lines of SQL and zero implementation code — the injected CustomerRepository is a Spring-generated proxy.
Common Mistakes & Pitfalls
- Writing an
Implclass —CustomerRepositoryImplcauses bean conflicts; Spring generates the implementation for you. - Confusing it with JpaRepository —
CrudRepositoryhas no pagination/sorting orflush(); for those, extendJpaRepository. - Wrong ID generic —
CrudRepository<Customer, String>when@IdisLongfails at runtime; the second type parameter must match the id type. - Expecting a
List—findAll()returnsIterable<T>; convert it (e.g. with a loop or stream) or useJpaRepositoryfor aList. - Ignoring the
Optional—findById()returnsOptional<T>; calling.get()on an empty one throwsNoSuchElementException.
Check your understanding
Answer these without looking back at the article.
- What is the difference between CrudRepository and JpaRepository?
- Why does findById return Optional?
- How does Spring Data generate the repository implementation?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.