Spring Data JPA & Repositories
Map objects to tables with JPA entities, and get CRUD for free from a repository interface you never implement.
On this page
BookVault's catalog has lived in a ConcurrentHashMap - it vanishes on restart. Time
to give it a real database. Doing that with raw JDBC means writing connection code,
SQL, and result-set mapping for every operation. Spring Data JPA removes almost
all of it: you describe your data as objects, declare a repository interface, and get
a full data-access layer you never implement.
Add the starter and a database
<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>H2 is an in-memory database - perfect for learning and tests. Swapping to PostgreSQL later is just a driver and a URL.
Map an object to a table: the entity
An entity is a class JPA maps to a database table. Annotations describe the mapping:
@Entity
class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // primary key, auto-generated
@Column(unique = true, nullable = false)
private String isbn;
private String title;
private String author;
private int copies;
protected Book() {} // JPA needs a no-arg constructor
// constructor, getters…
}Think of an object's data as a parcel and the database table as a warehouse of
numbered shelves. The entity annotations are the shipping form taped to the
parcel: @Table says which warehouse, @Id is the shelf number, @Column labels
each field's slot. JPA reads the form to file the object away and to fetch it back
later - you never walk the warehouse aisles (write SQL) yourself.
The repository: CRUD you never write
Declare an interface extending one of Spring Data's repository types, and Spring generates the implementation at runtime:
interface BookRepository extends JpaRepository<Book, Long> {
// that's it — save, findById, findAll, delete, count… all provided
}JpaRepository<Book, Long> means "manage Book entities with a Long id." You
immediately get save, findById, findAll, deleteById, count, and more - fully
implemented, transactional, and typed.
@Service
class BookService {
private final BookRepository repository;
BookService(BookRepository repository) { this.repository = repository; }
Book add(Book book) { return repository.save(book); }
List<Book> all() { return repository.findAll(); }
}You wrote no SQL and no implementation
There is no BookRepositoryImpl anywhere. Spring Data creates a proxy that turns your interface methods into queries and executes them. In the next lesson you'll add custom finders just by naming methods.
BookVault's BookService currently stores books in a Map<String, Book>. Describe the
two things you add to move it to a real database with Spring Data JPA - one on the
Book class, one new type - and note why you never write a class that implements the
data-access methods.
How do you obtain CRUD operations for an entity in Spring Data JPA?
Key takeaways
- Spring Data JPA maps objects to tables (@Entity, @Id, @Column) and generates data-access code for you.
- spring-boot-starter-data-jpa + an H2 (or PostgreSQL) driver sets up JPA/Hibernate and a datasource automatically.
- An entity is a class mapped to a table; it needs an @Id and a no-arg constructor.
- Declaring a repository interface extending JpaRepository<Entity, Id> gives you save/findById/findAll/delete for free - you never write the implementation.
- Switching databases later is mostly a driver and a connection URL change.