Spring Data JDBC

Spring Data

Let’s take a look

a.k.a Demo

You need

  • spring-boot-starter-data-jdbc

  • Aggregate Roots need an @Id

  • No getters/setter required

  • You can "wither" instead

Why Spring Data Jdbc?

We have already JPA

JPAs complexity

Lazy Loading (Exception)

Dirty Checking

Session / 1st Level Cache

Proxies for Entities

Map almost anything to anything

Spring Data JDBCs Design Choices

No Lazy Loading

No Caching

No Proxies

No deferred flushing

Very simple & limited & opinionated ORM

Simplicity is King

Complexity is tempting

Let’s see that in action

a.k.a more demo code

  • Clone: set ID to null and save again.

  • Loading the same entity creates multiple instances.

Death is for free

and it costs you your life.

Non trivial Aggregates

Design Challenge

CRUD Operations for entities with references

more Demo

One to N is fine

But what about Many-to-X?

⇒ No Many-to-X relations!


Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit.

— Martin Fowler

Repositories work on Aggregates

Aggregates are the basic element of transfer of data storage - you request to load or save whole aggregates.

— Martin Fowler

Aggregate Root

An aggregate will have one of its component objects be the aggregate root. Any references from outside the aggregate should only go to the aggregate root. The root can thus ensure the integrity of the aggregate as a whole.

— Martin Fowler

Many to X relations

If multiple Aggregate roots reference X,

X must be another Aggregate Root.

⇒ Not part of this Aggregate.

What is part of the Aggregate?

Everything referenced.

But Many-to-X is real!

  • Just reference an id.

Let’s look at code


  • Makes Aggregates obvious in code

  • Easier testing (no huge chains of dependencies)

  • Allows to pick a persistence strategy per Aggregate


Available Events

  • BeforeSaveEvent

  • AfterSaveEvent

  • BeforeDeleteEvent

  • AfterDeleteEvent

  • AfterLoadEvent - when an Aggregate got instantiated from the database


  • A model of the changes to be applied to the database

  • contains a list of DbAction s.


Represents a single SQL statement to be executed against the database.

Do whatever you want

  • Access the repository

  • change the entities


Enable Auditing Support


Add fields

String createdBy;
Instant createdAt;
String updatedBy;
Instant updatedAt;

Register AuditorAware

AuditorAware<String> auditorAware() {
  return new ModifiableAuditorAware();

AuditorAware example

public class ModifiableAuditorAware
    implements AuditorAware<String> {

  String value;

  public Optional<String> getCurrentAuditor() {
    return Optional.ofNullable(value);




@Query("select count(*) from address")
int countAddresses();


RowMapper / ResultSetExtractor

(Maybe) upcoming

Not promising anything.

Better CRUD


Derived Queries

Sorting and Paging

Named Queries with MyBatis

Named Queries via Properties

Is there reactive support?

Not in Spring Data JDBC

But in Spring Data R2DBC (not GA yet)


More References

Jens Schauder

Dad, Board&Roleplaying Gamer, Runner, Bouldering, Freeletics Masochist


JUG Organizer