1. JPA(Java Persistence API) 란?
- 자바 진영에서 사용하는 ORM(Object-Relational Mapping) 기술 표준
- 관계형 데이터베이스(RDB)를 자바 객체로 다루기 위한 인터페이스의 집합

2. ORM(Object-Relational Mapping) 이란?
- 객체(Object)와 관계형 데이터베이스(RDB)의 테이블을 매핑하는 기술
- 애플리케이션의 객체를 RDB 테이블에 자동으로 영속화(persistence) 해주는 기술
- 개발자는 객체만 다루고, 실제 SQL 생성과 실행은 ORM 프레임워크가 담당
3. ORM 장점
1) SQL이 아닌 객체 중심 개발
- SQL 대신 메서드 호출로 DB 조작
- 비즈니스 로직에 집중 가능
2) 반복 코드 제거
- CRUD SQL 작성 불필요
- 선언문, 매핑 코드 감소
3) 객체지향적인 설계 가능
- 상속, 연관관계, 캡슐화 등 OOP 개념 그대로 사용
- 생산성 증가
4) 유지보수와 리팩토링에 유리
- 매핑 정보가 클래스에 명시됨
- ERD 의존도 감소
5) DB 벤더 종속성 감소
- 타 db 변경 시(예, MySQL → PostgreSQL 변경)
- SQL 수정 없이 설정 변경만으로 대응 가능
4. JPA 의 단점
1) 잘못된 설계 시 성능 문제
: 대규모/복잡한 도메인에서 N+1 문제, 불필요한 조인 발생 가능
2) 복잡한 쿼리의 한계
: 통계성, 리포트성 쿼리는 튜닝 필요(결국 Native SQL 사용 가능성 존재)
3) 학습 비용
- 영속성 컨텍스트
- 지연 로딩, 즉시 로딩
- 변경 감지 등 개념 학습 필요
5. 왜 JPA를 사용해야 할까?
: SQL 중심 개발에서 객체 중심 개발로 전환
1) JPA가 제공하는 가치
- 반복적인 CRUD SQL 자동 처리
- 객체 관계를 기반으로 SQL 자동 생성
- 실행될 SQL 예측 가능
2) Native SQL 지원
- 성능 이슈
- 복잡한 쿼리 → 필요한 경우 직접 SQL 작성 가능
- 객체지향과 관계형 db 사이의 패러다임 불일치 이슈 해결
- 상속, 연관관계(조인) 등을 지원
6. 세팅 방법
- Gradle 의존성 설정 (build.gradle.kts)
plugins {
id("org.springframework.boot") version "3.2.0"
id("io.spring.dependency-management") version "1.1.0"
kotlin("jvm") version "1.9.10"
kotlin("plugin.spring") version "1.9.10"
kotlin("plugin.jpa") version "1.9.10"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
runtimeOnly("com.mysql:mysql-connector-j")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
- application.yml 설정
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC&useSSL=false
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: validate # create / create-drop / validate / update
show-sql: true # SQL 로그 확인
properties:
hibernate:
format_sql: true
use_sql_comments: true
- Entity
import jakarta.persistence.*
@Entity
@Table(name = "members")
data class Member(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
val username: String,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
var team: Team? = null
)
@Entity
@Table(name = "teams")
data class Team(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
val name: String
)
- repository
import org.springframework.data.jpa.repository.JpaRepository
interface MemberRepository : JpaRepository<Member, Long> {
fun findByUsername(username: String): Member?
}
interface TeamRepository : JpaRepository<Team, Long>
- service
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
@Service
class MemberService(
private val memberRepository: MemberRepository,
private val teamRepository: TeamRepository
) {
@Transactional
fun createMember(username: String, teamName: String): Member {
val team = Team(name = teamName)
teamRepository.save(team)
val member = Member(username = username, team = team)
return memberRepository.save(member)
}
@Transactional(readOnly = true)
fun getMember(id: Long): Member? {
return memberRepository.findById(id).orElse(null)
}
}'Kotlin Spring > Kotlin Spring 강의 내용' 카테고리의 다른 글
| [부록] Consumer Retry vs Command Replay 처리 (0) | 2026.02.03 |
|---|---|
| [부록] Docker for Mysql, Redis, Kafka (0) | 2026.01.26 |
| [부록] REST 기반 마이크로 서비스 간 통신 - OpenFeign (0) | 2026.01.20 |
| 10) Kafka 기반 도메인 분리(3) - Saga 패턴이란? (0) | 2026.01.14 |
| 10) Kafka 기반 도메인 분리 (4) Transactional Outbox 패턴이란? (0) | 2026.01.13 |