ORM의 정의 및 역할
ORM(Object-Relational Mapping)은 프로그램 객체와 RDB 레코드 간의 변환을 간략화하는 라이브러리입니다. 주요 역할은 다음과 같습니다.
-
DB 결과와 프로그래밍 언어 타입 간의 매핑
-
쿼리 발행 간략화 (DSL을 통한 쉬운 쿼리, CRUD 작업)
-
객체 생성 노력 해소 및 라이프사이클 관리
-
임피던스 불일치 해소 (타입 매핑, 데이터 구조 불일치 처리)
ORM의 유형
ORM은 크게 두 가지 패턴으로 나뉩니다.
-
Active Record 패턴: 엔티티와 리포지토리가 결합된 형태로, Rails의 ActiveRecord, Laravel의 Eloquent 등이 해당됩니다.
-
Data Mapper 패턴: 엔티티(데이터 구조)와 리포지토리(DB 접근 계층)가 분리된 형태로, Java의 Hibernate, PHP의 Doctrine 등이 있습니다. Ruby에서는 Hanami 프레임워크의
ruby-object-mapper가 이 패턴을 따릅니다. -
SQL Builder: 쿼리 발행에 중점을 두며, 객체 라이프사이클 관리는 SQL을 통해 이루어집니다. Java의 MyBatis, Ruby의 Sequel 등이 있습니다.
ActiveRecord의 특징 및 강점
ActiveRecord는 DB 마이그레이션, 유효성 검사, 커넥션 풀링 등 ORM 외의 다양한 기능을 포함하는 ‘올인원’ 라이브러리입니다. 주요 강점은 다음과 같습니다.
-
설정보다 규약(Convention over Configuration): 명시적인 매핑 없이 직관적인 데이터 조작이 가능합니다.
-
통합된 데이터 처리: 유효성 검사 및 스키마 관리를 통합하여 올인원 패키지로 제공합니다.
-
유연한 DSL: SQL을 몰라도 다양한 쿼리 발행이 가능하여 개발 생산성을 높입니다.
다른 ORM과의 비교
## 1. 쿼리 발행
-
ActiveRecord (Ruby):
Model.where.select와 같은 DSL로 직관적이고 쉬운 쿼리 발행이 가능하며, 연관관계 및 Enum 처리가 용이합니다. -
Prisma (TypeScript): ActiveRecord와 유사한 DSL을 제공하지만, 스키마 정의와 밀접하게 연동되어 타입 안전성을 보장합니다. 컴파일 시점에 타입 오류를 감지할 수 있습니다.
-
JPA (Java): 메소드 이름(
findByUserCreatedAtGreaterThanAndStatusOrderByCreatedAtAsc)을 통해 SQL을 발행하는 독특한 방식을 사용합니다. JPQL을 통해 SQL과 유사한 형태로 쿼리를 작성할 수도 있어 DSL의 한계를 벗어날 수 있습니다. -
MyBatis (Java, 2SQL): SQL 파일을 코드와 분리하여 관리하며, SQL 파일 내 주석을 통해 파라미터 바인딩을 처리하는 2SQL 방식을 사용합니다. DAO 인터페이스와 SQL 간의 컴파일 시점 검사를 통해 타입 안전성을 확보합니다.
2. 스키마 관리
-
ActiveRecord:
db:migrate명령어를 통해 DSL로 테이블 정의를 관리하고, 스키마 마이그레이션 테이블을 통해 버전 관리를 수행합니다. 모델의 프로퍼티는 DB 메타 정보를 통해 동적으로 매핑됩니다. -
Prisma:
prisma migrate dev명령어로 스키마 파일을 읽어 마이그레이션을 수행합니다. 특히, 선언적 마이그레이션(Declarative Migration)을 지원하여 스키마 변경 시 Prisma가 자동으로 ALTER TABLE 문을 생성해줍니다. 또한,prisma generate를 통해 스키마로부터 타입 정의를 자동 생성하여 타입 안전성을 높입니다. -
SQLC (Go): DB 스키마 변경과 애플리케이션 코드를 분리합니다.
schema.sql에서 구조체 타입을,.sql파일에서 리포지토리 인터페이스와 SQL을 생성하여 유연한 SQL 작성 및 타입 안전한 실행을 가능하게 합니다.
3. 다기능성 (All-in-one vs. Specialized)
-
ActiveRecord: 쿼리 DSL, 커넥션 풀, 스키마 관리 등 다양한 기능을 내장한 올인원 솔루션입니다.
-
Java: 커넥션 풀(HikariCP) 등 각 기능별로 전문화된 서드파티 라이브러리를 조합하여 사용하는 경우가 많습니다. 이는 유연한 커스터마이징이 가능하지만, 초기 설정의 복잡성이 증가하는 트레이드오프가 존재합니다.