spring-data-jpa

Spring Data JPA Implementation

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "spring-data-jpa" with this command: npx skills add a-pavithraa/springboot-skills-marketplace/a-pavithraa-springboot-skills-marketplace-spring-data-jpa

Spring Data JPA Implementation

Critical Rules

NEVER create repositories for every entity. ALWAYS create repositories only for aggregate roots.

NEVER use complex query method names. ALWAYS use @Query for non-trivial queries.

NEVER use save() blindly. ALWAYS understand persist vs merge semantics (see Vlad Mihalcea's guidance).

Step 1: Identify Repository Needs

Ask:

  • Is this an aggregate root? - Only aggregate roots get repositories

  • Query complexity? - Simple lookup or complex filtering?

  • Read vs Write? - Commands (write) or queries (read)?

  • Performance critical? - Large datasets, pagination, or projections?

Step 2: Choose Pattern

Pattern When Read

Simple Repository Basic CRUD, 1-2 custom queries

@Query Repository Multiple filters, joins, sorting references/query-patterns.md

DTO Projection Read-only, performance-critical references/dto-projections.md

Custom Repository Complex logic, bulk ops, Criteria API references/custom-repositories.md

CQRS Query Service Separate read/write, multiple projections references/cqrs-query-service.md

Decision criteria:

Need Simple @Query DTO Custom CQRS

Basic CRUD ✅ ✅ ❌ ✅ ✅

Custom Queries ❌ ✅ ✅ ✅ ✅

Best Performance ✅ ✅ ✅✅ ✅✅ ✅✅

Complex Logic ❌ ❌ ❌ ✅ ✅

Read/Write Separation ❌ ❌ ✅ ✅ ✅✅

Step 3: Implement Repository

Simple Repository

For basic lookups (1-2 properties):

public interface ProductRepository extends JpaRepository<ProductEntity, Long> { Optional<ProductEntity> findByCode(String code); List<ProductEntity> findByStatus(ProductStatus status); }

Asset: Use existing entity and repository patterns

@Query Repository

For 3+ filters, joins, or readability. Read: references/query-patterns.md

public interface OrderRepository extends JpaRepository<OrderEntity, Long> {

@Query("""
    SELECT DISTINCT o
    FROM OrderEntity o
    LEFT JOIN FETCH o.items
    WHERE o.userId = :userId
    ORDER BY o.createdAt DESC
    """)
List&#x3C;OrderEntity> findUserOrders(@Param("userId") Long userId);

}

Asset: assets/query-repository.java

  • Complete template with examples

DTO Projections

For read-only, performance-critical queries. Read: references/dto-projections.md

public record ProductSummary(Long id, String name, BigDecimal price) {}

@Query(""" SELECT new com.example.ProductSummary(p.id, p.name, p.price) FROM ProductEntity p WHERE p.status = 'ACTIVE' """) List<ProductSummary> findActiveSummaries();

Asset: assets/dto-projection.java

  • Records, interfaces, native queries

Custom Repository

For Criteria API, bulk ops. Read: references/custom-repositories.md

// 1. Custom interface public interface ProductRepositoryCustom { List<ProductEntity> findByDynamicCriteria(SearchCriteria criteria); }

// 2. Implementation (must be named <Repository>Impl) @Repository class ProductRepositoryImpl implements ProductRepositoryCustom { @PersistenceContext private EntityManager entityManager; // Implementation using Criteria API }

// 3. Main repository extends both public interface ProductRepository extends JpaRepository<ProductEntity, Long>, ProductRepositoryCustom { Optional<ProductEntity> findBySku(String sku); }

Asset: assets/custom-repository.java

  • Complete pattern

CQRS Query Service

For Tomato/DDD architectures. Read: references/cqrs-query-service.md

// Repository (package-private) - writes only interface ProductRepository extends JpaRepository<ProductEntity, ProductId> { Optional<ProductEntity> findBySku(ProductSKU sku); }

// QueryService (public) - reads only @Service @Transactional(readOnly = true) public class ProductQueryService {

private final JdbcTemplate jdbcTemplate;

public List&#x3C;ProductVM> findAllActive() {
    return jdbcTemplate.query("""
        SELECT id, name, price FROM products
        WHERE status = 'ACTIVE'
        """,
        (rs, rowNum) -> new ProductVM(
            rs.getLong("id"),
            rs.getString("name"),
            rs.getBigDecimal("price")
        )
    );
}

}

Asset: assets/query-service.java

  • Full CQRS pattern with JdbcTemplate

Step 4: Entity Relationships

Read: references/relationships.md for detailed guidance

Quick patterns:

// ✅ GOOD: @ManyToOne (most common) @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "order_id", nullable = false) private Order order;

// ✅ ALTERNATIVE: Just use ID (loose coupling) @Column(name = "product_id", nullable = false) private Long productId;

// ❌ AVOID: @OneToMany (query from many side instead) // Instead: List<OrderItem> items = itemRepository.findByOrderId(orderId);

// ❌ NEVER: @ManyToMany (create join entity instead) @Entity public class Enrollment { @ManyToOne private Student student; @ManyToOne private Course course; private LocalDate enrolledAt; }

Asset: assets/relationship-patterns.java

  • All relationship types with examples

Step 5: Performance Optimization

Read: references/performance-guide.md for complete checklist

Critical optimizations:

Prevent N+1 queries:

// Use JOIN FETCH @Query("SELECT o FROM Order o JOIN FETCH o.customer") List<Order> findWithCustomer();

// Or use DTO projection @Query("SELECT new OrderSummary(o.id, c.name) FROM Order o JOIN o.customer c") List<OrderSummary> findSummaries();

Use pagination:

Pageable pageable = PageRequest.of(0, 20); Page<Product> page = repository.findByCategory("Electronics", pageable);

Mark read services as readOnly:

@Service @Transactional(readOnly = true) public class ProductQueryService { }

Configure batch size:

spring.jpa.properties.hibernate.jdbc.batch_size: 25

Step 6: Transaction Management

Best practices:

@Service @Transactional(readOnly = true) // Class-level for read services public class ProductService {

public List&#x3C;ProductVM> findAll() {
    // Read operations
}

@Transactional  // Override for writes
public void createProduct(CreateProductCmd cmd) {
    ProductEntity product = ProductEntity.create(cmd);
    repository.save(product);
}

}

Rules:

  • Use @Transactional(readOnly = true) at class level for query services

  • Put @Transactional at service layer, not repository

  • Override with @Transactional for write methods in read services

Step 7: Testing

@DataJpaTest @Testcontainers @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) class ProductRepositoryTest {

@Container
static PostgreSQLContainer&#x3C;?> postgres =
    new PostgreSQLContainer&#x3C;>("postgres:16-alpine");

@Autowired
private ProductRepository repository;

@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.datasource.url", postgres::getJdbcUrl);
    registry.add("spring.datasource.username", postgres::getUsername);
    registry.add("spring.datasource.password", postgres::getPassword);
}

@Test
void shouldFindProductByCode() {
    ProductEntity product = createTestProduct("P001");
    repository.save(product);

    Optional&#x3C;ProductEntity> found = repository.findByCode("P001");

    assertThat(found).isPresent();
}

}

Anti-Patterns

Don't Do Why

Repository for every entity Only for aggregate roots Maintains boundaries

Use save() blindly Understand persist/merge Avoids unnecessary SELECT

Long query method names Use @Query Readability

findAll() without pagination Use Page<> or Stream Memory issues

Fetch entities for read views Use DTO projections Performance

FetchType.EAGER LAZY + JOIN FETCH Avoids N+1

@ManyToMany Use join entity Allows relationship attributes

@Transactional in repository Put in service layer Proper boundaries

Return entities from controllers Return DTOs/VMs Prevents lazy issues

Common Pitfalls

  1. LazyInitializationException

Problem: Accessing lazy associations outside transaction

Solution: Use DTO projection or JOIN FETCH

@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id") Optional<Order> findByIdWithItems(@Param("id") Long id);

  1. N+1 Queries

Problem: Loading associations in loop

Solution: See references/performance-guide.md

  1. Cartesian Product

Problem: Multiple JOIN FETCH with collections

Solution: Separate queries or DTO projections

Quick Reference

When to Load References

  • Multiple filters/joins needed → references/query-patterns.md

  • Read-only, performance-critical → references/dto-projections.md

  • Dynamic queries, bulk operations → references/custom-repositories.md

  • CQRS, read/write separation → references/cqrs-query-service.md

  • Entity associations → references/relationships.md

  • Slow queries, N+1 issues → references/performance-guide.md

Available Assets

All templates in assets/ :

  • query-repository.java

  • @Query examples, pagination, bulk ops

  • dto-projection.java

  • Records, interfaces, native queries

  • custom-repository.java

  • Criteria API, EntityManager

  • query-service.java

  • CQRS with JdbcTemplate

  • relationship-patterns.java

  • All JPA associations

References

Incorporates best practices from:

  • Vlad Mihalcea - Best Spring Data JpaRepository

  • Vlad Mihalcea - Spring Data JPA DTO Projections

  • Vlad Mihalcea - Spring Data Query Methods

  • Vlad Mihalcea - Spring Transaction Best Practices

  • Vlad Mihalcea - ManyToOne Best Practices

Browse vladmihalcea.com/blog for deep-dive articles.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

springboot-migration

No summary provided by upstream source.

Repository SourceNeeds Review
General

java25-springboot4-reviewer

No summary provided by upstream source.

Repository SourceNeeds Review
General

creating-springboot-projects

No summary provided by upstream source.

Repository SourceNeeds Review
General

spring-data-jpa

No summary provided by upstream source.

Repository SourceNeeds Review