Most Spring Boot services persist data in a relational database through Spring Data JPA.
Add spring-boot-starter-data-jpa and a JDBC driver (PostgreSQL, MySQL, or H2 for experiments). Boot configures a connection pool (HikariCP), Hibernate as the JPA provider and transaction management from the spring.datasource.* properties.
An entity is a class annotated @Entity with an @Id (often @GeneratedValue). Fields map to columns; @Column, @Table and relationship annotations (@ManyToOne, @OneToMany) customise the mapping. Entities need a no-argument constructor (it can be protected), and they are mutable classes, not records.
A repository is just an interface: interface BookRepository extends JpaRepository<Book, Long> {}. Spring Data generates the implementation at startup with save, findById (returns Optional), findAll, deleteById, count, paging and sorting.
Derived queries come from method names: findByAuthor(String a), findByTitleContainingIgnoreCase(String s), countByPublishedAfter(LocalDate d), findTop5ByOrderByPublishedDesc(). A typo in the name fails at startup, not at runtime. For anything complex, write JPQL with @Query("select b from Book b where ...").
Schema management: spring.jpa.hibernate.ddl-auto defaults to create-drop for embedded databases only. For real databases manage the schema with Flyway or Liquibase migrations, and keep ddl-auto=validate or none.
Example
@Entity
class Book {
@Id @GeneratedValue Long id;
String title;
String author;
LocalDate published;
protected Book() {} // required by JPA
Book(String title, String author, LocalDate published) {
this.title = title; this.author = author; this.published = published;
}
}
interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByAuthorIgnoreCase(String author);
List<Book> findByTitleContainingIgnoreCase(String fragment);
long countByPublishedAfter(LocalDate date);
@Query("select b from Book b where b.published < :date order by b.published")
List<Book> classicsBefore(@Param("date") LocalDate date);
}
@Service
class Catalog {
private final BookRepository repo;
Catalog(BookRepository repo) { this.repo = repo; }
Book add(String t, String a, LocalDate d) { return repo.save(new Book(t, a, d)); }
Optional<Book> find(long id) { return repo.findById(id); }
}Remember
@Entity+@Idmaps a class to a table- Extend
JpaRepository<T, ID>and get CRUD, paging and sorting for free - Derived query methods are parsed from names and checked at startup
- Use Flyway or Liquibase for schema changes, not ddl-auto
Watch out for
- Using spring.jpa.hibernate.ddl-auto=update in production, which can't handle renames and drifts silently.