Level 2 · Intermediate Data & Security¶
Goal: turn the in-memory API from Level 1 into a real service — backed by a relational database with versioned migrations, covered by fast and realistic tests, protected by Spring Security with JWT bearer tokens, and documented with OpenAPI.
This is the level where most day-to-day Spring Boot work lives. It is also where the framework's abstractions start to leak: JPA's persistence context, transaction boundaries, and the security filter chain all behave in ways that surprise people who only learned the annotations. Each lesson's How It Actually Works section is there so those surprises become predictable.
Modules¶
- Spring Data JPA & Hibernate Basics — JPA vs Hibernate vs Spring Data, data sources, and the persistence context
- Entities & Relationships — mapping tables,
@ManyToOne/@OneToMany, owning sides, cascades, and equality - Repositories, Derived Queries & @Query — query methods, JPQL, projections, paging, and sorting
- Transactions with @Transactional — boundaries, propagation, rollback rules, and read-only transactions
- Database Migrations with Flyway — versioned SQL,
ddl-auto: validate, and safe schema evolution - Testing: JUnit 5, Slices & Testcontainers — unit tests,
@WebMvcTest,@DataJpaTest, and real databases in tests - Spring Security Fundamentals — the filter chain, authentication vs authorization, and password storage
- JWT & the OAuth2 Resource Server — validating bearer tokens, scopes, and identity providers
- API Documentation with springdoc-openapi — generating an OpenAPI spec and Swagger UI from your code
- Project — A Secured Library API with a Database — authors and books with JPA, Flyway, JWT security, and tests
What you need before starting¶
- Level 1 completed, especially configuration, validation, and exception handling.
- Basic SQL:
SELECTwith joins, primary and foreign keys, indexes. The SQL Mastery Path covers this. - Optional but recommended: Docker, for running PostgreSQL locally and for Testcontainers. Lessons use the in-memory H2 database where possible so everything also runs without Docker, and say so explicitly when something needs a real database.