spring-data-jdbc

v2026.09.24

Spring Data JDBC for simple, lightweight database access without JPA complexity. Covers aggregates, repositories, custom queries, and DDD patterns. USE WHEN: user mentions "spring data jdbc", "simple database access", "no JPA", "aggregate roots", "DDD with JDBC", "lightweight ORM", "@MappedCollection" DO NOT USE FOR: JPA/Hibernate features - use `spring-data-jpa` instead, reactive database - use `spring-r2dbc` instead, NoSQL - use respective skills

GitHub
Install command
npx skhub add claude-dev-suite/spring-data-jdbc
Markdown
SKILL.md

Spring Data JDBC - Quick Reference

Full Reference: See advanced.md for custom row mappers, ID generation, auditing, event listeners, and Testcontainers integration.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: spring-data-jdbc for comprehensive documentation.

Why Spring Data JDBC over JPA?

Spring Data JDBCSpring Data JPA
No lazy loadingLazy loading
No dirty checkingAuto dirty checking
No session/cacheFirst-level cache
Explicit SQLGenerated SQL
Fast startupSlower startup

Dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>

Entity Mapping

@Table("users")
public class User {
    @Id
    private Long id;
    private String username;
    private String email;

    @Column("created_at")
    private LocalDateTime createdAt;
}

Aggregate Design

@Table("orders")
public class Order {
    @Id
    private Long id;
    private Long customerId;  // Reference by ID, not entity
    private OrderStatus status;

    @MappedCollection(idColumn = "order_id")
    private Set<OrderItem> items = new HashSet<>();

    public void addItem(Long productId, int quantity, BigDecimal price) {
        items.add(new OrderItem(productId, quantity, price));
    }

    public BigDecimal getTotal() {
        return items.stream()
            .map(OrderItem::getSubtotal)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}

// Aggregate member (no @Id - lifecycle managed by root)
public class OrderItem {
    private Long productId;
    private int quantity;
    private BigDecimal unitPrice;

    public BigDecimal getSubtotal() {
        return unitPrice.multiply(BigDecimal.valueOf(quantity));
    }
}

Repository Pattern

public interface OrderRepository extends CrudRepository<Order, Long> {

    List<Order> findByCustomerId(Long customerId);
    List<Order> findByStatus(OrderStatus status);

    @Query("SELECT * FROM orders WHERE status = :status ORDER BY created_at DESC LIMIT :limit")
    List<Order> findRecentByStatus(OrderStatus status, int limit);

    @Modifying
    @Query("UPDATE orders SET status = :newStatus WHERE status = :oldStatus AND created_at < :before")
    int updateOldOrders(OrderStatus oldStatus, OrderStatus newStatus, LocalDateTime before);

    boolean existsByCustomerIdAndStatus(Long customerId, OrderStatus status);
}

Schema

CREATE TABLE orders (
    id BIGSERIAL PRIMARY KEY,
    customer_id BIGINT NOT NULL,
    status VARCHAR(50) NOT NULL
);

CREATE TABLE order_item (
    order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
    product_id BIGINT NOT NULL,
    quantity INT NOT NULL,
    unit_price DECIMAL(10, 2) NOT NULL
);

When NOT to Use This Skill

  • Need lazy loading - Use spring-data-jpa for complex entity graphs
  • Reactive applications - Use spring-r2dbc for non-blocking access
  • Complex ORM features - Use JPA for second-level cache, dirty checking

Anti-Patterns

Anti-PatternProblemSolution
JPA-style entity graphsNot supportedDesign proper aggregates
Embedding other aggregatesCouplingReference by ID only
Large aggregatesPerformance issuesKeep aggregates small
Missing CASCADE on FKOrphan recordsAdd ON DELETE CASCADE

Quick Troubleshooting

ProblemDiagnosticFix
Entity not savedCheck @Id generationConfigure ID callback or auto-increment
Children not persistedCheck @MappedCollectionAdd idColumn properly
Column not mappedCheck namingUse @Column for custom names
Transaction not workingCheck @TransactionalEnsure Spring proxy

Best Practices

DoDon't
Design proper aggregatesUse JPA-style entity graphs
Reference other aggregates by IDEmbed other aggregate roots
Keep aggregates smallCreate huge aggregate graphs
Use immutable value objectsMutate embedded objects directly

Production Checklist

  • Aggregate boundaries defined
  • Schema matches entity mapping
  • Indexes on query columns
  • Foreign keys with CASCADE
  • Transaction boundaries clear
  • Connection pool configured

Reference Documentation

Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

skills/databases/spring-data-jdbc

Default branch

main

Latest commit

9496306

Tree SHA

fe4e2f1