A repository gives application code a place to ask for data without putting database operations in a controller. In a taco-ordering application, an ingredient repository can find and save ingredients; an order repository can save an order. Each interface describes the operations its callers need. How those operations reach the database depends on the persistence approach. section 3.1.2 section 3.1.4
package tacos.data;
import java.util.Optional;
import tacos.Ingredient;
public interface IngredientRepository {
Iterable<Ingredient> findAll();
Optional<Ingredient> findById(String id);
Ingredient save(Ingredient ingredient);
}
The IngredientRepository interface declares three useful operations: find all ingredients, find one by ID, and save one. It does not contain SQL. section 3.1.2
With JdbcTemplate, declaring that interface is only the first step. A class must implement it: queries fetch rows, a row mapper turns them into Ingredient objects, and an update inserts an ingredient. Marking the class @Repository makes it discoverable as a Spring bean. A controller can then receive an IngredientRepository through its constructor and call findAll() without handling those database details. section 3.1.2
Spring Data removes the need to write that implementation class for common operations. Extend one of its repository interfaces and Spring Data creates the implementation when the application starts. CrudRepository already supplies methods such as those needed by the ingredient and order repositories; its type parameters identify the entity and its ID type. section 3.2.2
Listing 3.13 Defining a repository interface for persisting ingredients
package tacos.data;
import org.springframework.data.repository.CrudRepository;
import tacos.Ingredient;
public interface IngredientRepository
extends CrudRepository<Ingredient, String> {
}
This Spring Data JDBC version keeps IngredientRepository to a single declaration. CrudRepository supplies the common operations, so the interface need not repeat them. section 3.2.2
Keep these practical differences in mind:
- Saving an order with a handwritten JDBC repository takes more work than saving one ingredient: the order, its tacos, and ingredient links must all be persisted, and generated IDs must be captured. section 3.1.4
- The same CrudRepository declarations work with Spring Data JDBC and JPA. Cassandra and MongoDB repositories look similar, but the order ID type changes with the stored entity. section 3.3.3 section 4.2.3
- Repository interfaces can also declare additional methods for custom queries when common CRUD operations are not enough. section 4.1.4
The takeaway: define the data operations the application needs, then choose whether to implement them with JdbcTemplate or let Spring Data provide the repository. Reactive repositories follow a similar persistence goal, though R2DBC’s lack of direct domain-relationship support can require a different design. section 3.1.2 section 3.2.2 section 13.4








