Chapter 4.2☕ 16 min read

Connecting to DB & JpaRepository CRUD

One interface, all CRUD operations for free.

01The Concept: The Magic Repository

Now that we have an @Entity, how do we save it to the database? Do we need to write INSERT INTO book... SQL? No. Spring Data JPA provides the JpaRepository interface, which gives us all CRUD operations for free.

The Amazon Fulfillment Center Analogy:

Imagine Amazon's massive warehouse in Hyderabad. As a seller, you don't walk into the warehouse and physically build a shelf for your product. You just hand the product to the warehouse manager. The manager knows how to store it, find it later, or throw it away.

In Spring Boot, JpaRepository is that warehouse manager. You just create an interface and extend JpaRepository. You don't write the implementation class. Spring Boot looks at your interface and dynamically writes the implementation code at runtime to save, find, update, and delete objects in the database!

02Technical Explanation
  1. JpaRepository<T, ID>: An interface provided by Spring Data JPA.
    T is your Entity type (e.g., Book).
    ID is the data type of your Primary Key (e.g., Long).
  2. Built-in Methods: It instantly gives you save(), findById(), findAll(), deleteById(), etc., without writing a single line of SQL.
03Full Working Code: Repository and Controller

Let's wire the database to our REST API.

package com.devinhyderabad;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

// 1. The Magic Interface. Spring provides the implementation automatically.
interface BookRepository extends JpaRepository<Book, Long> {
// It's empty, but it has save(), findById(), findAll(), deleteById()!
}
04The CRUD Controller in Action
@RestController
@RequestMapping("/api/books")
class BookController {

// 2. Inject the repository
private final BookRepository bookRepository;

public BookController(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}

// 3. CREATE: Uses save() to insert into DB
@PostMapping
public ResponseEntity<Book> createBook(@RequestBody Book book) {
Book savedBook = bookRepository.save(book);
return ResponseEntity.status(HttpStatus.CREATED).body(savedBook);
}

// 4. READ ALL: Uses findAll()
@GetMapping
public List<Book> getAllBooks() {
return bookRepository.findAll();
}

// 5. READ ONE: Uses findById() and handles 404
@GetMapping("/{id}")
public ResponseEntity<Book> getBookById(@PathVariable Long id) {
return bookRepository.findById(id)
.map(book -> ResponseEntity.ok(book))
.orElse(ResponseEntity.notFound().build());
}

// 6. DELETE: Uses deleteById()
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
if (bookRepository.existsById(id)) {
bookRepository.deleteById(id);
return ResponseEntity.noContent().build(); // 204 No Content
}
return ResponseEntity.notFound().build();
}
}

Test this in Postman:

  1. POST a book: {"title":"Spring Guide","author":"Deva"}
  2. GET all books. You will see your book has been assigned an ID!
  3. Restart your app. The data will be gone because H2 is in-memory, but the table was automatically created.
05Why It Matters / Interview Note

Interview Question: "How does Spring Data JPA provide implementations for your repository interfaces?"

Answer: Spring uses dynamic proxies. At application startup, it scans for interfaces extending Repository. It creates a proxy class that implements your interface, and routes method calls (like save() or findById()) to the default implementation provided by SimpleJpaRepository, which under the hood uses Hibernate to execute the actual SQL.

Enterprise Note: Notice the use of map() and orElse() with findById(). findById() returns an Optional<Book>. This functional programming style prevents NullPointerException and makes handling 404s very elegant.

Key Takeaways

  • ✅ JpaRepository provides all CRUD operations with zero implementation code
  • ✅ Spring uses dynamic proxies to create repository implementations at runtime
  • ✅ findById() returns Optional — use map() and orElse() for clean handling
  • ✅ JpaRepository<T, ID> is parameterised with your Entity and PK types