Learn Spring Boot - Data Access & Repositories
Episode 6 of 24

Learn Spring Boot - Data Access & Repositories

This episode teaches data access with Spring Data JPA: mapping tables via @Entity, creating repositories with CrudRepository, using query methods and custom queries with @Query, configuring the datasource, and using H2 for prototyping.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Your API in episode 5 still uses hardcoded data. It's time to store data in a database. Episode 6 introduces Spring Data JPA — the most common way to access relational databases in Spring Boot.

You'll learn to map tables into Java objects, create repositories that provide CRUD operations for free, write automatic and custom queries, and set up a datasource — from in-memory H2 for development to PostgreSQL for production.

Spring Data JPA and Entities

Adding the Dependencies

To get started, add the JPA starter dependency and the database driver to pom.xml. With Spring Initializr, just choose Spring Data JPA and H2 Database. If the project already exists, add them manually:

JPA and H2 dependencies in pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

The spring-boot-starter-data-jpa starter pulls in Hibernate as the JPA implementation, spring-data-jpa, and the default HikariCP connection pool.

Mapping a Table with @Entity

An entity is a Java class that represents a table. Each entity instance is one row in the table:

Item entity
@Entity
@Table(name = "items")
public class Item {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
 
    @Column(nullable = false)
    private String name;
 
    private String description;
}

@Entity marks the class as a JPA entity, @Id defines the primary key, @GeneratedValue sets up auto-increment, and @Table sets the table name. Hibernate will create the schema automatically according to the ddl-auto configuration.

Repositories and Automatic CRUD

CrudRepository and JpaRepository

A repository is an interface that handles queries. Just declare an interface that extends CrudRepository or JpaRepository, and Spring Data provides a complete implementation of CRUD operations:

Automatic CRUD repository
public interface ItemRepository extends CrudRepository<Item, Long> {
}

Without writing a single line of implementation, this repository already provides methods like save, findById, findAll, count, and deleteById. This is the power of Spring Data: the patterns that always repeat are generated automatically.

Using the Repository in a Service

Wire the repository into the service via constructor injection:

Service using a repository
@Service
public class ItemService {
 
    private final ItemRepository repository;
 
    public ItemService(ItemRepository repository) {
        this.repository = repository;
    }
 
    public Item create(Item item) {
        return repository.save(item);
    }
 
    public Optional<Item> findById(Long id) {
        return repository.findById(id);
    }
}

The repository.save(item) call inserts a new row or updates an existing one, and repository.findById(id) returns an Optional that's empty if the data isn't found.

Query Methods and Custom Queries

Automatic Query Methods

Spring Data can derive queries from method names. For example, findByNameContaining will produce a WHERE name LIKE %value% query:

Automatic query methods
public interface ItemRepository extends CrudRepository<Item, Long> {
 
    List<Item> findByNameContaining(String keyword);
 
    List<Item> findByDescriptionIsNotNullOrderByNameAsc();
}

The thought rule is simple: start with findBy, then name the field being filtered, and end with modifiers such as Containing, OrderBy, or Between. The full keyword list is available in the Spring Data documentation.

Custom Queries with @Query

For complex queries or native SQL, use @Query:

Custom JPQL and native queries
public interface ItemRepository extends CrudRepository<Item, Long> {
 
    @Query("SELECT i FROM Item i WHERE i.name LIKE %:k%")
    List<Item> cariByName(@Param("k") String keyword);
 
    @Query(value = "SELECT COUNT(*) FROM items WHERE name = :n",
           nativeQuery = true)
    long countByName(@Param("n") String name);
}

The first query uses JPQL — an object-oriented query. The second uses native SQL directly against the database. Choose JPQL for portability and native for cases that need database-specific SQL.

Datasource Configuration

In-Memory H2 for Development

Spring Boot's default uses in-memory H2 — a database that disappears every time the application stops, suitable for prototyping. Enable the explicit configuration and the H2 console:

H2 configuration
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.hibernate.ddl-auto=create-drop
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

The setting spring.jpa.hibernate.ddl-auto=create-drop asks Hibernate to create the schema at startup and drop it at shutdown. The H2 console can be accessed at /h2-console to inspect the database contents.

PostgreSQL for Production

For a more realistic environment, switch the datasource to PostgreSQL:

PostgreSQL configuration
spring.datasource.url=jdbc:postgresql://localhost:5432/belajar
spring.datasource.username=belajar
spring.datasource.password=rahasia
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

In production, use validate so Hibernate only checks the schema without modifying it. The proper schema migration strategy with Flyway or Liquibase will be covered in episode 10.

Closing

Episode 6 equipped you with data access using Spring Data JPA: mapping tables with @Entity, creating automatic CRUD repositories via CrudRepository, writing query methods and custom queries with @Query, and configuring H2 and PostgreSQL datasources.

Key takeaways:

  • @Entity maps a Java class to a database table; @Id marks the primary key.
  • A repository interface extending CrudRepository provides CRUD without implementation.
  • Query methods like findByNameContaining derive queries from method names.
  • @Query writes JPQL or native SQL queries explicitly.
  • In-memory H2 suits development; use ddl-auto=create-drop.
  • For production use PostgreSQL with ddl-auto=validate and managed migrations.

In the next episode, episode 7, we'll discuss validation and exception handling — Jakarta Bean Validation with @Valid, @NotNull, and @Size, custom validation annotations, global exception handling with @ControllerAdvice and @ExceptionHandler, and a consistent error response format for your API.

Learn Spring Boot - Data Access & Repositories | Learn Spring Boot