From ecc
Spring Boot에서 엔터티 설계, 관계 설정, 쿼리 최적화, 트랜잭션, 감사, 인덱싱, 페이지네이션, 커넥션 풀링을 위한 JPA/Hibernate 패턴입니다.
npx claudepluginhub sam42-lab/everything-claude-code-krThis skill uses the workspace's default tool permissions.
Spring Boot에서 데이터 모델링, repository, 성능 튜닝에 사용합니다.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Spring Boot에서 데이터 모델링, repository, 성능 튜닝에 사용합니다.
@OneToMany, @ManyToOne, @ManyToMany)를 정의할 때@Entity
@Table(name = "markets", indexes = {
@Index(name = "idx_markets_slug", columnList = "slug", unique = true)
})
@EntityListeners(AuditingEntityListener.class)
public class MarketEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 200)
private String name;
@Column(nullable = false, unique = true, length = 120)
private String slug;
@Enumerated(EnumType.STRING)
private MarketStatus status = MarketStatus.ACTIVE;
@CreatedDate private Instant createdAt;
@LastModifiedDate private Instant updatedAt;
}
Auditing 활성화:
@Configuration
@EnableJpaAuditing
class JpaConfig {}
@OneToMany(mappedBy = "market", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PositionEntity> positions = new ArrayList<>();
JOIN FETCHEAGER는 피하고 읽기 경로는 DTO projection을 선호@Query("select m from MarketEntity m left join fetch m.positions where m.id = :id")
Optional<MarketEntity> findWithPositions(@Param("id") Long id);
public interface MarketRepository extends JpaRepository<MarketEntity, Long> {
Optional<MarketEntity> findBySlug(String slug);
@Query("select m from MarketEntity m where m.status = :status")
Page<MarketEntity> findByStatus(@Param("status") MarketStatus status, Pageable pageable);
}
Projection 예시:
public interface MarketSummary {
Long getId();
String getName();
MarketStatus getStatus();
}
Page<MarketSummary> findAllBy(Pageable pageable);
@Transactional@Transactional(readOnly = true)@Transactional
public Market updateStatus(Long id, MarketStatus status) {
MarketEntity entity = repo.findById(id)
.orElseThrow(() -> new EntityNotFoundException("Market"));
entity.setStatus(status);
return Market.from(entity);
}
PageRequest page = PageRequest.of(pageNumber, pageSize, Sort.by("createdAt").descending());
Page<MarketEntity> markets = repo.findByStatus(MarketStatus.ACTIVE, page);
cursor 유사 페이지네이션은 id > :lastId 형태로 구현합니다.
select * 대신 필요한 컬럼만 projectionsaveAll과 hibernate.jdbc.batch_size 활용권장 속성:
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.validation-timeout=5000
PostgreSQL LOB 처리:
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
@DataJpaTest + Testcontainers를 선호합니다엔터티는 가볍게, 쿼리는 의도적으로, 트랜잭션은 짧게 유지합니다. fetch 전략, projection, 인덱스로 N+1을 방지합니다.