spring-data-jpa

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

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 claude-dev-suite/claude-dev-suite/claude-dev-suite-claude-dev-suite-spring-data-jpa

Spring Data JPA

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

Entity with Auditing

@Entity @Table(name = "users") @Data @NoArgsConstructor @AllArgsConstructor @Builder @EntityListeners(AuditingEntityListener.class) public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, length = 100)
private String name;

@Column(unique = true, nullable = false)
private String email;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private UserRole role = UserRole.USER;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private UserStatus status = UserStatus.ACTIVE;

@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;

@LastModifiedDate
private LocalDateTime updatedAt;

@CreatedBy
@Column(updatable = false)
private String createdBy;

@LastModifiedBy
private String updatedBy;

}

Repository Interface

@Repository public interface UserRepository extends JpaRepository<User, Long> {

// Derived query methods
Optional&#x3C;User> findByEmail(String email);
boolean existsByEmail(String email);
List&#x3C;User> findByStatus(UserStatus status);
List&#x3C;User> findByRoleIn(List&#x3C;UserRole> roles);

// Query with JPQL
@Query("SELECT u FROM User u WHERE u.status = :status AND u.role = :role")
List&#x3C;User> findByStatusAndRole(
    @Param("status") UserStatus status,
    @Param("role") UserRole role
);

// Native query
@Query(value = "SELECT * FROM users WHERE email LIKE %:domain", nativeQuery = true)
List&#x3C;User> findByEmailDomain(@Param("domain") String domain);

// Pagination
Page&#x3C;User> findByNameContainingIgnoreCase(String name, Pageable pageable);

// Sorting
List&#x3C;User> findByStatus(UserStatus status, Sort sort);

// Modifying queries
@Modifying
@Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
int updateStatus(@Param("id") Long id, @Param("status") UserStatus status);

@Modifying
@Query("DELETE FROM User u WHERE u.status = :status")
int deleteByStatus(@Param("status") UserStatus status);

}

Relationships

// One-to-Many @Entity public class Department { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;

@OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
private List&#x3C;Employee> employees = new ArrayList&#x3C;>();

}

@Entity public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id", nullable = false)
private Department department;

}

// Many-to-Many @Entity public class User { @ManyToMany(fetch = FetchType.LAZY) @JoinTable( name = "user_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id") ) private Set<Role> roles = new HashSet<>(); }

Pagination & Sorting

@Service public class UserService {

public Page&#x3C;UserResponse> findAll(int page, int size, String sortBy, String direction) {
    Sort sort = Sort.by(Sort.Direction.fromString(direction), sortBy);
    Pageable pageable = PageRequest.of(page, size, sort);
    return userRepository.findAll(pageable)
        .map(userMapper::toResponse);
}

public Page&#x3C;UserResponse> search(String query, Pageable pageable) {
    return userRepository.findByNameContainingIgnoreCase(query, pageable)
        .map(userMapper::toResponse);
}

}

// Controller @GetMapping public ResponseEntity<Page<UserResponse>> findAll( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size, @RequestParam(defaultValue = "createdAt") String sortBy, @RequestParam(defaultValue = "desc") String direction) { return ResponseEntity.ok(userService.findAll(page, size, sortBy, direction)); }

Specifications (Dynamic Queries)

public class UserSpecifications {

public static Specification&#x3C;User> hasStatus(UserStatus status) {
    return (root, query, cb) ->
        status == null ? null : cb.equal(root.get("status"), status);
}

public static Specification&#x3C;User> hasRole(UserRole role) {
    return (root, query, cb) ->
        role == null ? null : cb.equal(root.get("role"), role);
}

public static Specification&#x3C;User> nameContains(String name) {
    return (root, query, cb) ->
        name == null ? null : cb.like(cb.lower(root.get("name")),
            "%" + name.toLowerCase() + "%");
}

}

// Repository extends JpaSpecificationExecutor public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {}

// Usage Specification<User> spec = Specification .where(UserSpecifications.hasStatus(UserStatus.ACTIVE)) .and(UserSpecifications.hasRole(UserRole.ADMIN)) .and(UserSpecifications.nameContains("john"));

List<User> users = userRepository.findAll(spec);

Enable Auditing

@Configuration @EnableJpaAuditing public class JpaConfig {

@Bean
public AuditorAware&#x3C;String> auditorProvider() {
    return () -> Optional.ofNullable(SecurityContextHolder.getContext())
        .map(SecurityContext::getAuthentication)
        .filter(Authentication::isAuthenticated)
        .map(Authentication::getName);
}

}

Key Annotations

Annotation Purpose

@Entity

JPA entity

@Table

Table mapping

@Id

Primary key

@GeneratedValue

Auto-generation strategy

@Column

Column mapping

@ManyToOne / @OneToMany

Relationships

@Query

Custom JPQL/SQL

@Modifying

Update/Delete queries

@CreatedDate / @LastModifiedDate

Auditing

When NOT to Use This Skill

  • Spring Boot application setup → Use spring-boot skill

  • REST API patterns → Use spring-web skill

  • MongoDB operations → Use mongodb-expert skill

  • Security configuration → Use spring-security skill

  • Raw SQL optimization → Use sql-expert skill

  • Reactive database access → Use spring-r2dbc skill

Anti-Patterns

Anti-Pattern Why It's Bad Correct Approach

N+1 queries Poor performance Use @EntityGraph or fetch joins

Missing @Transactional

Data inconsistency Always use for write operations

Bidirectional relations without care Infinite recursion Use @JsonManagedReference/@JsonBackReference

Fetch EAGER everywhere Loads unnecessary data Use LAZY, fetch only when needed

No pagination Memory issues Always paginate large results

Query in loop Performance killer Use batch fetch or single query

Quick Troubleshooting

Problem Likely Cause Solution

LazyInitializationException Accessing lazy field outside transaction Fetch in transaction or use @EntityGraph

MultipleBagFetchException Multiple @OneToMany EAGER fetch Use @EntityGraph or separate queries

Slow queries Missing indexes or N+1 Add indexes, check query logs

No query results Wrong method name Follow naming convention or use @Query

Constraint violation Entity state mismatch Check cascade and orphanRemoval

DetachedEntityException Entity not managed Use merge() or reload entity

Reference Documentation

  • Spring Data JPA Reference

  • Query Methods

  • Specifications

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.

Coding

spring-data-jpa

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

cron-scheduling

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

token-optimization

No summary provided by upstream source.

Repository SourceNeeds Review