Spring Data JPA Introduction
Spring Data JPA eliminates boilerplate database code. Write an interface, Spring generates the implementation.
JPA, Hibernate, and Spring Data JPA
Spring Data JPA ← High-level abstraction (interfaces)
│
Hibernate ← JPA implementation (ORM)
│
JDBC ← Low-level database communication
│
Database ← PostgreSQL, MySQL, H2, etc.
| Layer | Role |
|---|---|
| JPA | Specification (standard API for ORM) |
| Hibernate | Implementation of JPA |
| Spring Data JPA | Removes boilerplate — repositories from interfaces |
Setup
<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>
spring:
datasource:
url: jdbc:h2:mem:bookstoredb
driver-class-name: org.h2.Driver
username: sa
password:
h2:
console:
enabled: true
path: /h2-console
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
properties:
hibernate:
format_sql: true
Visit http://localhost:8080/h2-console and connect with JDBC URL jdbc:h2:mem:bookstoredb.
Your First Entity
@Entity
@Table(name = "books")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 200)
private String title;
@Column(nullable = false)
private String author;
@Column(unique = true, length = 17)
private String isbn;
private BigDecimal price;
@Column(name = "published_date")
private LocalDate publishedDate;
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
// Default constructor required by JPA
protected Book() {}
public Book(String title, String author, String isbn, BigDecimal price) {
this.title = title;
this.author = author;
this.isbn = isbn;
this.price = price;
}
// getters and setters...
}
Your First Repository
public interface BookRepository extends JpaRepository<Book, Long> {
// That's it! Spring generates the implementation
}
You instantly get:
| Method | SQL Equivalent |
|---|---|
save(book) |
INSERT / UPDATE |
findById(1L) |
SELECT WHERE id = 1 |
findAll() |
SELECT * |
findAll(pageable) |
SELECT with LIMIT/OFFSET |
deleteById(1L) |
DELETE WHERE id = 1 |
count() |
SELECT COUNT(*) |
existsById(1L) |
SELECT EXISTS |
Using the Repository
@Service
public class BookService {
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
public List<Book> findAll() {
return bookRepository.findAll();
}
public Book findById(Long id) {
return bookRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Book", id));
}
public Book create(CreateBookRequest request) {
Book book = new Book(
request.title(), request.author(),
request.isbn(), request.price()
);
return bookRepository.save(book);
}
}
ddl-auto Options
| Value | Behavior | Use |
|---|---|---|
create-drop |
Create on start, drop on stop | Dev/testing |
create |
Create on start (drop existing) | Dev |
update |
Alter tables to match entities | Dev (risky) |
validate |
Validate schema, don’t change | Production |
none |
Do nothing | Production (use Flyway) |
Production: always use
validateornonewith Flyway/Liquibase for migrations.
Key Takeaways
- Spring Data JPA = JPA + Hibernate + auto-generated repositories.
- Extend
JpaRepository<Entity, IdType>— get CRUD for free. - H2 is perfect for development — in-memory, zero setup.
- Use
create-dropfor dev,validatefor production. - Always define a protected no-arg constructor for JPA entities.
What’s Next?
Next: JPA Entities and Repositories — @Entity, @Table, @Id, column mappings, and repository methods.